我不熟悉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;
}
答案 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
为第二个。)