mih*_*mek 6 where-clause julia
对于 Julia 手动参数复合类型示例
struct Point{T}
x::T
y::T
end
Run Code Online (Sandbox Code Playgroud)
可以编写一个外部构造函数,例如
Point(x::T, y::T) where {T} = Point{T}(x, y)
Run Code Online (Sandbox Code Playgroud)
为什么where {T}需要零件,即为什么不需要
Point(x::T, y::T) = Point{T}(x, y)
Run Code Online (Sandbox Code Playgroud)
可能的?Julia 抱怨T没有定义,但它不能T从::语法中找出它是一种类型吗?我是 Julia 的新手,所以我可能会遗漏一些非常基本的东西。
T是一个必须定义的变量。如果你没有在whereJulia 中定义它,就会开始在外部作用域中寻找它。下面是一个例子:
julia> struct Point{T}
x::T
y::T
end
julia> Point(x::T, y::T) = Point{T}(x, y)
ERROR: UndefVarError: T not defined
Stacktrace:
[1] top-level scope at REPL[2]:1
julia> T = Integer
Integer
julia> Point(x::T, y::T) = Point{T}(x, y)
Point
julia> Point(1,1)
Point{Integer}(1, 1)
Run Code Online (Sandbox Code Playgroud)
请注意,在此示例中,您没有得到预期的结果,这可能是您所希望的Point{Int64}(1,1)。
现在最棘手的部分来了:
julia> Point(1.5,1.5)
Point{Float64}(1.5, 1.5)
Run Code Online (Sandbox Code Playgroud)
你可能会问这是怎么回事。好:
julia> methods(Point)
# 2 methods for type constructor:
[1] (::Type{Point})(x::Integer, y::Integer) in Main at REPL[4]:1
[2] (::Type{Point})(x::T, y::T) where T in Main at REPL[1]:2
Run Code Online (Sandbox Code Playgroud)
关键是 The(::Type{Point})(x::T, y::T) where T已经在默认情况下被定义,当struct定义为第二个定义时,您刚刚为T = Integer.
简而言之 - 总是使用where以避免获得令人惊讶的结果。例如,如果你会写:
julia> T = String
String
julia> Point(1,1)
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
Run Code Online (Sandbox Code Playgroud)
你有问题。由于 的签名在Point定义时是固定的,但在正文中T是从全局范围中获取的,并且您已将其从 更改Integer为String,因此您会收到错误消息。
扩展@Oscar Smith 指出的位置where对范围也很敏感,并告诉 Julia 在什么级别引入了“通配符”。例如:
ulia> T1 = Vector{Vector{T} where T<:Real}
Array{Array{T,1} where T<:Real,1}
julia> T2 = Vector{Vector{T}} where T<:Real
Array{Array{T,1},1} where T<:Real
julia> isconcretetype(T1)
true
julia> isconcretetype(T2)
false
julia> T1 isa UnionAll
false
julia> T2 isa UnionAll
true
julia> x = T1()
0-element Array{Array{T,1} where T<:Real,1}
julia> push!(x, [1,2])
1-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
julia> push!(x, [1.0, 2.0])
2-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
[1.0, 2.0]
Run Code Online (Sandbox Code Playgroud)
你可以看到这T1是一个可以有实例的具体类型,我们创建了一个调用它的类型x。这种具体类型可以保存元素类型为 的向量<:Real,但它们的元素类型不必相同。
另一方面T2是一个UnionAll,即它的一些“通配符”是免费的(还不知道)。但是,限制是在匹配T2所有向量的所有具体类型中必须具有相同的元素类型,因此:
julia> Vector{Vector{Int}} <: T2
true
julia> Vector{Vector{Real}} <: T2
true
Run Code Online (Sandbox Code Playgroud)
但
julia> T1 <: T2
false
Run Code Online (Sandbox Code Playgroud)
换句话说,T2通配符中必须有一个具体值可以与具体类型匹配。
我将采取与 Bogumi? 出色答案不同的策略(100% 正确,但可能会忽略混淆的症结所在)。
这个名字没有什么特别之处T。这只是任意类型的短名称的常见约定。有点像我们经常在A矩阵或ifor 循环中使用这个名称。您碰巧在struct Point{T}和 外部构造函数中使用了相同的名称这一事实无关紧要(但对于您的代码的读者来说很方便)。你也可以做得很好:
struct Point{SpecializedType}
x::SpecializedType
y::SpecializedType
end
Point(x::Wildcard, y::Wildcard) where {Wildcard <: Any} = Point{Wildcard}(x, y)
Run Code Online (Sandbox Code Playgroud)
这和你写的完全一样。上述两种语法(结构体和方法)都引入了一个新名称,该名称的行为类似于专门进行适当匹配的“通配符”。当您没有where子句时,您不再引入通配符。相反,您只是引用已定义的类型。例如:
Point(x::Int, y::Int) = Point{Int}(x, y)
Run Code Online (Sandbox Code Playgroud)
也就是说,这将引用Int已经定义的 。
我想你可以说,但如果T没有定义,为什么 Julia 不能弄清楚它应该用作通配符。这可能是对的,但它在语法中引入了一点非局部性,根据定义的内容(甚至从使用的包导出),行为会截然不同。
| 归档时间: |
|
| 查看次数: |
430 次 |
| 最近记录: |