Julia 中的构造函数:根据其他命名字段的输入值初始化命名字段

Posted

技术标签:

【中文标题】Julia 中的构造函数:根据其他命名字段的输入值初始化命名字段【英文标题】:Constructors in Julia: initializing named fields based on the input value of other named fields 【发布时间】:2015-05-29 14:38:36 【问题描述】:

想象一个构造函数,它接受两个参数并使用两个参数的值初始化 3 个命名字段。像这样的:

type test1
   a
   b
   c
   test1(a,b) = new(a,b,a/b)
end

这很好用,但是如果 c 的值不是这么简单的表达式怎么办?如果它超过一两行怎么办?或者是一个复杂的列表理解?将c 的表达式直接粘贴到new() 中很笨拙,并且使代码更难阅读(IMO)。我宁愿做这样的事情:

type test1
   a
   b
   c = a/b
   test1(a,b) = new(a,b,c)
end

但是 ab 显然是在调用 test1(a,b) 之前定义的,所以这不起作用。也许我只是在寻找语法糖。无论如何,我想更好地理解构造函数的参数值何时已知以及是否可以在调用new().之前使用它们。

有没有更好的方法(比第一个示例更好)来做我在第二个示例中尝试做的事情?

(我认为以下问题及其答案的相关性足以提供帮助,但我仍然是 Julia 新手Building a non-default constructor in Julia)

已编辑:冒着过于具体的风险,我想我会包括出现这个问题的实际用例。我正在做一个自适应集成方案。跨越积分边界的每个体积元素都被进一步细分。我对“立方体”类型的定义如下。我的学生在 python 中编写了一个工作原型,但我试图在 julia 中重写它以提高性能。

using Iterators
# Composite type defining a cube element of the integration domain
type cube
    pos # floats: Position of the cube in the integration domain
    dx  # float: Edge length of the cube
    verts # float: List of positions of the vertices 
    fvals::Dict # tuples,floats: Function values at the corners of the cube and its children
    depth::Int # int: Number of splittings to get to this level of cube
    maxdepth::Int # Deepest level of splitting (stopping condition)
    intVal # float: this cube's contribution to the integral

    intVal = 0

    cube(pos,dx,depth,maxdepth) = new(pos,dx,
           [i for i in product(0:dx:dx,0:dx:dx,0:dx:dx)],
           [vt=>fVal([vt...]) for vt in [i for i in product(0:dx:dx,0:dx:dx,0:dx:dx)]],
           depth,maxdepth,intVal)
end

【问题讨论】:

【参考方案1】:

内部构造函数只是出现在与类型同名的类型块中的函数。这意味着您可以使用function syntax 来定义它们。您可以使用简写形式(如上所述),也可以使用更详细的块语法:

type test1
   a
   b
   c
   function test1(a,b)
      c = a/b
      return new(a,b,c)
   end
end

new 的调用甚至不需要是方法中的最后一个表达式;您可以将其结果分配给中间变量,然后返回它。


更多细节:type 块就像普通的 Julia scope 一样,但有一些例外:

任何单独出现或与类型注释一起出现的符号都将成为该类型的字段。 函数可以访问特殊的 new 内置函数来实例化类型,与类型同名的函数成为内部构造函数。

当您将任何其他赋值放入类型块中时,它们只会在该范围内创建一个局部变量。它不是字段或类型的一部分,而只是可以在构造函数的方法中使用的变量。也就是说,它不是很有用,可能会change in the future。

【讨论】:

这真的很有帮助。谢谢。我特别感谢最后的额外细节以及您对我的第二个示例的修改,这正是我想要的。我没有意识到其他函数语法(block syntax)可以用于内部构造函数。我应该更仔细地阅读Case Study: Rational【参考方案2】:

使用 Matt B. 的答案,我为我的特定用例构建了以下答案。对函数使用块语法更简洁。

using Iterators
# Composite type defining a cube element of the integration domain
type cube
    pos # floats: Position of the cube in the integration domain
    dx  # float: Edge length of the cube
    verts # tuple: List of positions of the vertices 
    fvals # floats: Function values at the corners of the cube and its children
    depth::Int # int: Number of splittings to get to this level of cube
    maxdepth::Int # Deepest level of splitting (stopping condition)

    function cube(pos,dx,depth,maxdepth)
        verts = [pos+[vt...].*dx for vt in product(0:1,0:1,0:1)]
        fvals = [fVal([vt...]) for vt in verts ]
        return new(pos,dx,verts,fvals,depth,maxdepth)
    end
end

【讨论】:

以上是关于Julia 中的构造函数:根据其他命名字段的输入值初始化命名字段的主要内容,如果未能解决你的问题,请参考以下文章

在 Julia 中构建非默认构造函数

Julia 中的复合类型:作为命名字段的字典?

PHP:根据二维数组中的某个字段进行排序

Vuejs 根据从下拉列表中选择的值显示其他输入字段

如何使用Optim最小化Julia中的多元成本函数?

如何在构造函数的重载函数中使用子类中的字段值