实例化Type时的关键字参数

时间:2015-03-25 16:38:34

标签: julia

假设我有以下类型:

type Foo
    a::Int64
    b::Int64
end

我可以用

实例化
bar = Foo(1,2)

有没有办法在这里使用关键字,因为在上面我必须记住a是第一个,而b是第二个。像这样:

bar = Foo(a=1, b=2)

修改

如果从函数调用,spencerlyon2的解决方案不起作用:

#!/usr/bin/env julia

type Foo
    a::Float64
    b::Float64
end

function main()
    Foo(;a=1, b=2.0) = Foo(a,b)
    bar = Foo(a=1, b=2.0)
    println(bar.a)
end

main()

为什么呢?有解决方法吗?

编辑2

不在函数内部工作:

#!/usr/bin/env julia

type Foo
    a::Int64
    b::Int64
end

function main()
    Foo(;a=1, b=2) = Foo(a,b)
    bar = Foo(a=1, b=2)
    println(bar.a)
end

main()

但如果将其从功能中取出 - 它可以工作:

#!/usr/bin/env julia

type Foo
    a::Int64
    b::Int64
end

# function main()
    Foo(;a=1, b=2) = Foo(a,b)
    bar = Foo(a=1, b=2)
    println(bar.a)
# end

# main()

1 个答案:

答案 0 :(得分:5)

是的,但您需要参数的默认值:

julia> type Foo
           a::Int64
           b::Int64
       end

julia> Foo(;a=1, b=2) = Foo(a, b)
Foo

julia> Foo(b=10)
Foo(1,10)

julia> Foo(a=40)
Foo(40,2)

julia> Foo(a=100, b=200)
Foo(100,200)

修改

让我们分解语法Foo(;a=1, b=1) = Foo(a, b)

首先,定义与类型同名的函数为该类型定义新的构造函数。这意味着我们正在定义另一个将创建Foo类型对象的函数。手册中有一个whole chapter个构造函数,所以如果你不熟悉这个术语,你应该阅读它们。

其次,Julia区分位置和关键字参数。位置参数是Julia中的默认参数。使用位置参数,根据定义参数的顺序将名称分配给函数参数,然后将其传递给函数。例如,如果我定义一个函数f(a, b) = ....,我知道我传递给f的第一个参数将在函数体内被称为a(无论名称是什么)变量在调用范围内。)

在Julia中,关键字参数的处理方式不同。在调用函数时,使用语法argument=value为函数的关键字参数提供非默认值。在Julia中,您告诉编译器某些参数是关键字参数,方法是使用分号(;)将它们与标准位置参数分开并赋予它们默认值。例如,如果我们定义g(a; b=4) = ...,我们可以通过将a作为第一个传递给gb的值来为b=something提供值g。如果我们想使用参数a=4b=5来调用g(4; b=5)函数,我们会写;(注意,这里可以替换为{{1}但是我发现它有助于我记住b是一个关键字参数,如果我改为使用;

有了这个,我们终于可以理解上面的语法:

Foo(;a=1, b=2) = Foo(a, b)

这会创建一个新的构造函数,其零位置参数和两个关键字参数:ab,其中a的默认值为1和{{1默认为b。该函数声明的右侧只需要2a并将它们传递给默认的内部构造函数(在我们声明类型时自动为我们定义){{1} }。


编辑2

我找出了在函数中定义新的外部构造函数时遇到的问题。

b

实际上创建了一个全新的函数Foo,它是function main() Foo(;a=1, b=2.0) = Foo(a,b) 函数的本地函数。因此,左侧会创建一个新的本地Foo,右侧会尝试调用该新的本地main。问题是没有为本地Foo定义的方法采用两个位置Foo参数。

如果你真的想要这样做,你需要告诉Foo函数通过指定Int64属于全局范围来向main外部函数添加方法。这有效:

Foo

关于使用内部构造函数。当然你可以这样做,但你也想要定义一个默认的内部构造函数。这是因为如果您没有定义任何新的内部构造函数,Julia会为您生成一个默认构造函数。如果您决定创建自己的一个,那么如果您想拥有它,则必须手动创建默认构造函数。这样做的语法是

Foo

我应该注意,对于这个特定的用例,你几乎肯定不希望将关键字版本定义为内部构造函数,而是将其作为外部构造函数,就像我在答案开始时所做的那样。 Julia中的约定是尽可能使用最少数量的内部构造函数 - 仅在需要确保字段之间的不变关系或部分初始化对象的情况下使用它们。