未在函数主体中指定泛型类型参数时,该如何访问?

Mas*_*son 3 julia

假设我有

struct X{T} end
Run Code Online (Sandbox Code Playgroud)

以及在上调度的函数,如果未在方法签名中指定函数主体X,如何T在函数主体内部进行访问?即

function foo(x::X)
    # can i get T in here?
end
Run Code Online (Sandbox Code Playgroud)

这是对julialang松弛问题的重述:https ://julialang.slack.com/archives/C6A044SQH/p1568651904113000

要获得访问权限,只需填写以下表格:https : //slackinvite.julialang.org

Mas*_*son 5

最好的方法是定义一个访问器函数:

getparam(::X{T}) where {T} = T
Run Code Online (Sandbox Code Playgroud)

然后一个人可以做

function foo(x::X)
    T = getparam(x)
    ...
end
Run Code Online (Sandbox Code Playgroud)

只要您没有通过解释器运行julia,就应该在编译时消除所有类型检查。例如:


julia> foo(x::X) = getparam(x) + 1
foo (generic function with 1 method)

julia> foo(X{1}())
2

julia> @code_llvm foo(X{1}())

;  @ REPL[24]:1 within `foo'
define i64 @julia_foo_19216() {
top:
  ret i64 2
}

julia> @code_llvm foo(X{2}())

;  @ REPL[24]:1 within `foo'
define i64 @julia_foo_19221() {
top:
  ret i64 3
}
Run Code Online (Sandbox Code Playgroud)

如您所见,编译器能够弄清楚它可以在编译时用替换调用foo(X{2})3而完全没有运行时开销。


附带说明,这应该有助于说明为什么类型稳定性很重要。如果我们做过类似的事情foo(X{rand(Int)}),则编译器将无法访问类型参数,直到它foo在运行时到达为止,然后需要针对rand(Int)最终评估的结果编译特定的方法,这将非常缓慢:

julia> @btime foo(X{rand(Int)}())
  2.305 ms (1962 allocations: 125.49 KiB)
-3712756042116422157
Run Code Online (Sandbox Code Playgroud)

哎呀,这是slooooow!为了比较,

julia> bar(x) = x + 1
bar (generic function with 1 method)

julia> @btime bar(rand(Int))
  9.746 ns (0 allocations: 0 bytes)
5990190339309662951
Run Code Online (Sandbox Code Playgroud)