Polymorphism 我可以写一个有效的方法吗;“只要可能”;像一个c++;模板功能?

Polymorphism 我可以写一个有效的方法吗;“只要可能”;像一个c++;模板功能?,polymorphism,julia,Polymorphism,Julia,rand适用于以下范围: rand(1:10) 我想让rand与Array以及任何可索引且具有长度的东西一起工作: import Base.Random rand(thing) = thing[rand(1:length(thing))] array = {1, 2, 3} myRand(array) range = 1:8 myRand(range) tupple = (1, 2, 3, "a", "b", "c") myRand(tupple) …但如果我尝试这样做,我的实现堆栈就

rand
适用于以下范围:

rand(1:10)
我想让
rand
Array
以及任何可索引且具有
长度的东西一起工作:

import Base.Random
rand(thing) = thing[rand(1:length(thing))]

array = {1, 2, 3}
myRand(array)

range = 1:8
myRand(range)

tupple = (1, 2, 3, "a", "b", "c")
myRand(tupple)
…但如果我尝试这样做,我的实现堆栈就会溢出,可能是因为它完全通用并且匹配所有传递的内容,所以它最终会调用自己

有办法解决这个问题吗?我想更好地理解Julia的多态函数,而不是修复这个特殊的(可能是愚蠢的)函数专业化

是否还有一个工具来发现可用的各种实现,并调试将使用特定参数调用的实现


好的,一些挖掘。这很有趣

我将启动一个新的REPL,并且:

julia> import Base.Random

julia> rand(thing) = thing[rand(1:length(thing))]
rand (generic function with 1 method)

julia> rand({1,2,3})
ERROR: stack overflow
 in rand at none:1 (repeats 80000 times)
…哦,天哪,这就是我刚才说的递归调用和堆栈溢出

但是,看这个。我杀了茱莉亚,然后重新开始。这次我
导入Base.Random.rand

julia> import Base.Random.rand

julia> rand(thing) = thing[rand(1:length(thing))]
rand (generic function with 33 methods)

julia> rand({1,2,3})
3
它可以工作——它将我的新实现添加到所有其他实现中,并选择了正确的实现

因此,我的第一个问题的答案似乎是——“它只是起作用”。这太神奇了。这是怎么回事


但是有一个听起来不太有趣的关于模块的问题,以及为什么导入Base.Random
没有引入
rand
方法或给出错误,但是
import Base.Random.rand
有。

我本想对此发表评论,但结果太长了:

请注意,还有两种方法也“有效”:

或者您也可以使用:

importall Base.Random
rand(thing) = thing[rand(1:length(thing))]
rand({1,2,3})
当您仅使用
import Base.Random
时,实际上不允许您使用本地定义的
rand
扩展
Base.rand
。这是因为
import
语句只能用于函数,而不能用于模块。如果要导入模块中的所有函数,需要使用
importall
(如上面的示例所示)。或者(正如我上面所做的),您可以直接在函数定义
Base.rand
中引用模块

不可否认,上次我翻阅文件时,这一点肯定可以说得更清楚。不过,最新版本中可能会提到这一点

至于你问题的其余部分(为什么它“只起作用”?),我不相信我能给出一个聪明简洁的答案,所以我可能会把它留给其他人


另外,.

正如另一位指出的那样,显式指定
Base.rand=
而不是
rand=
将方法添加到Base中的
rand
函数定义中,而不是完全替换它

比如说,

julia> Base.rand(x::Any)=x[rand(1:length(x)]
rand (generic function with 33 methods)
这项工作的原因与朱莉娅的有关。当Julia查找具有匹配方法签名的函数时,它从定义类型的叶节点开始(例如,x是否为Int8),然后向上移动类型层次结构,直到找到具有匹配签名的函数。在类型层次结构的顶部是catchall类型Any。如果层次结构的任何级别都没有匹配的函数,则函数调用失败

这可以通过一个简单的例子得到最好的说明。我们将创建一个函数f,该函数用类型的名称响应类型层次结构中的几个不同类型:

julia> f(x::Int)="Int"
f (generic function with 1 method)

julia> f(x::Real)="Real"
f (generic function with 2 methods)

julia> f(x::Number)="Number"
f (generic function with 3 methods)

julia> f(x::Any)="Any"
f (generic function with 4 methods)

julia> f(x::Array)="Array"
f (generic function with 5 methods)

julia> f(4) # typeof(4) isInt64
"Int"

julia> f(2.0) # typeof(2.0) is Float64
"Real"

julia> f(3im) # typeof(3im) is Complex{Int64}

"Number"

julia> f([1,2]) # typeof([1,2]) is Array{Int64, 1}
"Array"

julia> f(Dict(1=>3,4=>5)) # typeof(Dict(1=>3,4=>5)) is Dict{Int64, Int64}
"Any" 
方法扩展 正如一些人所指出的,Julia允许您扩展函数:您可以有不同类型的函数(请参阅)

例如:

f(x) = 2
f(x::Int) = x
在本例中,我们有一个函数的版本(或方法),当(且仅当)参数类型为
Int
时调用该函数。第一个是另一个

我们说我们已经扩展了
f
函数,现在它有两种方法

你的问题 那么,您想要的是扩展
rand
函数

如果使用其他方法未捕获的参数调用
rand
函数,则需要执行
thing[rand(1:length(thing))]
。如果操作正确,您将调用应用于
范围
对象的
rand
方法,因为您将
1:length(thing)
作为参数传递

虽然有缺陷(如果
东西
没有长度,例如复数),但我认为您的第一次尝试是非常合理的

问题
rand
无法在程序的第一个版本上扩展。根据,编写
import Base.Random
不会使
rand
可用于方法扩展

在尝试扩展
rand
时,实际上覆盖了
rand
函数。在此之后,当您调用函数
rand
时,只有您的方法

请记住,您所依赖的事实是,在elsewere中定义了一个范围方法(例如,
rand(1:10)
),并且它给出了您期望的结果。发生的情况是,这个方法被您的方法覆盖,所以再次调用您的方法(递归)

解决方案:导入
rand
,使其可用于扩展。您可以在文档的表格上看到这一点

请注意,您的第二个程序(带有
import Base.Random.rand
)和Colin的程序(带有
import Base.Random
)正是这样做的。这就是他们工作的原因


请记住哪些方法可用于扩展,哪些方法不可用于扩展,如果文档不够清晰,欢迎提供错误报告(或修复)。

嗨,科林,谢谢你的回答–我不知道为什么你会被否决,因为你所说的与其他答案一致,似乎是正确的,而且很有帮助!从我这里得到+1,让你回到0。谢谢你的回答。@Benjohn是的,奇怪的否决票。不用担心:-)我关心的是帮助你,如果我做到了,那么我很高兴。谢谢你的回答,太好了。
f(x) = 2
f(x::Int) = x