9

我正在考虑编写类似于NamedArraysImages中定义的类型。假设我只想要一个带有元数据的数组,比如一个用户友好的名称,当我将数组写入磁盘时,我将在文件顶部写入该名称。(这个细节无关紧要;我只是在设计一个例子。)

所以我可能会

type MyNamedArray
    data::Array
    name::ASCIIString
end

function mywrite(f,x::MyNamedArray)
     write(f,x.name)
     write(f,x.data)
end

或其他东西,并且没有其他行为需要与基本 Array 行为不同。

在我的脑海中,“很明显”我只希望在数组上运行的每个现有函数都在data这种类型的字段上运行。在另一种语言(例如 Java)中,我可能只是将 Array 子类化并name作为实例字段添加到子类中,这将自动保持与所有现有 Array 操作的兼容性。但是在 Julia 中,如果我尝试使用上述解决方案,我现在需要定义更多函数,例如 @TimHoly 和 'davidavdav' 在链接包中所做的那样。

当然,我知道被迫手动写出其中一些函数对于实现您尚未考虑过的事情很有用。例如,在MyNamedArray我上面给出的示例中,可以通过指出我没有定义x::MyNamedArray * y::MyNamedArray. 但是,如果我只是不关心这一点,并且想要“正常工作”的代码而没有这么多样板怎么办?(参见例如循环符号以在 NamedArrays中推送新方法定义,并在Images中手动写出一百行定义。这些定义中的绝大多数都是样板文件/“显而易见的”定义。)

具体来说,继续我引用的示例,对于MyNamedArray,默认值可能x*y不再是 a MyNamedArray,即因为每个函数只是默认为在基础数据上应用相同函数的“继承”行为,我们可以忘记所有 pre 上的元数据- 现有功能。

请注意,我发现 Tomas Lycken 在这里的回答很有见地,这里问题和答案也是如此。

我能想到的最好的综合是“你只需要把它吸起来,写出函数,或者写一个宏来为你做这件事。” 如果是这样,那就这样吧;我只是想知道我是否错过了更好的选择,特别是设计解决方案以使其更加朱利安并避免样板的更好方法。

4

1 回答 1

6

您可以通过简单的子类化获得大部分方式:http AbstractArray: //docs.julialang.org/en/latest/manual/interfaces/#abstract-arrays。事实上,你可以做一个更好的子类DenseArray,这还需要定义一个stride(并且可能pointer)函数……允许你的自定义数组与 BLAS 一起工作。这只是您需要定义的少数方法。这不是 100%,因为许多作者仍然倾向于过度限制方法,只Array在他们可以轻松接受 all时才接受AbstractArrays。在过去的两年里,这一点已经明显好转,而且还在不断改进。

一般来说,我在这里发现一个非常有用的模式是根据抽象超类型定义接口并尽可能地放松方法签名。如果不需要调度限制,您可以允许任何类型并且只依赖鸭子类型。如果您在告诉 Julia 应该如何 quack 或依靠其内部实现时仅将调度限制为特定的叶类型,那么您的工作将变得更具可扩展性和可重用性。

于 2016-06-07T19:25:05.920 回答