Julia中的重载与覆盖

时间:2018-05-29 11:59:41

标签: operator-overloading julia super method-overriding

我不熟悉Julia,但我觉得我注意到它允许您使用不同的签名多次定义函数,例如this

FK5Coords{e}(ra::T, dec::T) where {e,T<:AbstractFloat} = FK5Coords{e, T}(ra, dec)
FK5Coords{e}(ra::Real, dec::Real) where {e} =
   FK5Coords{e}(promote(float(ra), float(dec))...)

对我来说,这似乎允许您使用两个不同的签名来呼叫FK5Coords

所以我想知道(a)如果这是真的,如果Julia允许这样的overloading functions,以及(b)如果Julia在函数中允许super这样的东西,这似乎是与超载冲突。并且(c),Julia代码的示例片段在一个示例中显示(1)重载,以及(2)覆盖另一个示例。

我问的原因是因为我想知道Julia如何解决同时具有super和函数重载的问题,因为两者都需要再次定义函数,而且似乎你必须用一些元数据标记它或者说“在这种情况下我是压倒一切”或“在这种情况下我超载”。

注意:如果那不是重载的例子,那么(来自维基百科)这就是我想象的Julia支持(沿着这些方向):

// volume of a cylinder
double volume(const double r, const int h)
{
    return 3.1415926*r*r*static_cast<double>(h);
}

// volume of a cuboid
long volume(const long l, const int b, const int h)
{
    return l*b*h;
}

1 个答案:

答案 0 :(得分:2)

  

所以我想知道(a)如果这是真的,如果Julia允许重载这样的函数

Julia允许您编写相同函数的不同版本(函数的不同“方法”),这些版本在参数的类型/数量上有所不同。这非常类似于重载,除了重载通常意味着要调用的函数是基于参数的编译时类型决定的,而在Julia中它是根据参数的运行时类型决定的。这通常称为动态调度。请参阅this C++ example,了解重载缺失和发送给您的内容。

  

(b)如果Julia在函数中允许类似super的东西,这似乎会与重载冲突   我问的原因是因为我想知道Julia如何解决超级和函数重载的问题,因为两者都需要再次定义函数,而且似乎你必须用一些元数据标记它或者说“在这里case我压倒“或”在这种情况下我超载“。

我不确定为什么你认为重载会与super发生冲突。在C ++中,重写涉及具有完全相同的参数编号和类型,而重载需要使参数的数量或类型不同。编译器足够聪明,可以轻松区分这两种情况,AFAICT C ++ 可以具有super方法,尽管它具有重载和覆盖,除了它还具有多重继承。我相信(凭借我有限的C ++知识)多重继承是C ++没有super方法调用而不是重载的原因。

无论如何,如果你在面向对象的幕后剥离并查看方法签名,你会发现所有重写都是特定类型的重载:Dog::run(int dist, int dir)可以覆盖Animal::run(int dist, int dir)(假设Dog继承自Animal),但这相当于使用run(Animal a, int dist, int dir)定义重载run(Dog d, int dist, int dir)函数。 (如果run是一个虚函数,这将是动态调度而不是重载,但这是一个单独的讨论。)

在朱莉娅,我们明确地这样做,因此定义将是run(d::Dog, dist::Int, dir::Int)run(a::Animal, dist::Int, dir::Int)。但是,在Julia中,你只能继承抽象类型,所以这里的超类型Animal是一个抽象类型,所以你不能用Animal实例调用第二个方法 - 第二个方法定义实际上是简化的说法是“为Animal的某个具体子类型的任何实例调用此方法,除非该子类型有自己独立的方法定义”(在这种情况下,Dog会这样做)。我不知道从第一个run(Animal...调用第二个方法run(Dog...的简单方法,这相当于super调用。

(您也可以使用import“覆盖”来自其他模块的方法,但如果它具有完全相同的参数和参数类型,您可能会提交type piracy,这通常是在这种类型的覆盖之后,我不知道有什么方法可以取回原始方法。“通过定义和使用自己的类型来重载”(使用调度)更常见。)

  

(c),Julia代码的示例片段在一个示例中显示(1)重载,以及(2)覆盖另一个示例。

您发布的第一个代码段是使用调度的示例(这是Julia使用而不是重载的内容)。再举一个例子,让我们首先定义我们的基类型和函数:

abstract type Vehicle end
function move(v::Vehicle, dist::Float64)
  println("Moving by $dist meters")
end

现在我们可以用这种方式创建这个函数的另一个方法来调度(“重载”它):

function move(v::Vehicle, dist::LightYears)
  println("Blazing across $dist light years")
end

我们也可以做一个面向对象的风格“覆盖”(虽然在语言层面上这只是另一种调度方法):

struct Car <: Vehicle
  model::String
end
function move(c::Car, dist::Float64)
  println("$model is moving $dist meters")
end

这相当于将派生类中的Vehicle.move(float dist)覆盖为Car.move(float dist)

只是为了它,问题的音量函数:

# volume of a cylinder
volume(r::Float64, h::Int) = π*r*r*h
volume(l::Int, b::Int, h::Int) = l*b*h;

现在调用的正确volume方法将根据传递的参数的数量(和类型)来决定(并且返回类型由编译器自动推断,Float64用于第一种方法, Int为第二个。)