この記事について
引数の型指定について、応用的なことをまとめる。
このあたりのことは、ドキュメントで散発的にしか出てこなかったり、直接的には書かれていなかったりするので、挙動やコードから推測しているところもある。
引数の型パラメータを指定する
Int64 <: Integer # true
Vector{Int64} <: Vector{Integer} # false
Vector{Int64} <: Vector{T} where T<:Integer # true
Vector{<:Integer} == Vector{T} where T<:Integer
f1(x::Vector{T}) where T<:Integer = x
f2(x::Vector{<:Integer}) = x
f1([1, 2]) # [1, 2]
f2([1, 2]) # [1, 2]
https://docs.julialang.org/en/v1/manual/methods/#Parametric-Methods-1
https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types-1
複合体の型パラメータのスーパータイプを指定する
関数の引数ではないけれど、私がよく混乱するところなので書き留めておく。
struct MyType{T<:Number}
a :: T
end
MyType(3) # MyType{Int64}(3)
前節の書き方と混同してこのように間違えがちなのである。
struct MyType{T} where T<:Number
a :: T
end
# ERROR: syntax: invalid type signature
型パラメータを省略する
# Array{T,N}
Array{Int} == Array{Int,N} where N
Array{Int,2} <: Array{Int} <: Array
型を作るときには、ここを考慮した上で型パラメータの順番を決めるとよいだろう。指定したい型パラメータを先に配置し、省略しそうな型パラメータを後にするのが便利である。
例外:タプルの型
タプルは関数引数の抽象化なので、ここまでの説明とは挙動が全く異なる。
# パラメータの包含関係が連鎖する (covariant)
Tuple{Int64} <: Tuple{Integer} # true
# パラメータは省略できない(2引数と1引数は異なるメソッド)
Tuple{Int,String} <: Tuple{Int} # false
可変長引数の型を指定する
Function parameters can also be used to constrain the number of arguments that may be supplied to a "varargs" function.
https://docs.julialang.org/en/v1/manual/functions/#Varargs-Functions-1
https://docs.julialang.org/en/v1/manual/types/#Vararg-Tuple-Types-1
https://docs.julialang.org/en/v1/manual/methods/#Parametrically-constrained-Varargs-methods-1
AbstractArray
インターフェースで getindex
を実装するときなど、引数の個数が N 個のとき、 Vararg{T,N}
で指定できる。
https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array-1
# 等価な表現
f1(args::Int...) = args
f2(args::Vararg{Int}) = args
f1(1, 2) # (1, 2)
f2(1, 2) # (1, 2)
struct MyArray{T,N,A<:AbstractArray{T,N}} <: AbstractArray{T,N}
arr :: A
end
Base.size(A::MyArray) = size(A.arr)
Base.getindex(A::MyArray, I::Vararg{Int}) = A.arr[I...]
MyArray(rand(10, 10))[3, 4]
追記: NTuple{N,T}
と関係がある
Tuple{Vararg{Int,3}} == NTuple{3,Int}
型を引数にとる
型 T
の型は Type{T}
で指定できる。
typeof(Int64) # DataType
Int64 isa Type{Int64}
f1(typ::Type{Int64}) = typ
f1(Int64) # Int64
f2(typ::Type{T}) where T<:Integer = typ
f2(Int32) # Int32
isa(AbstractVector, Type{AbstractArray{<:Any,N}} where N)
!isa(AbstractVector, Type{AbstractArray{T,<:Any}} where T)
Type{>:Missing} == Type{Union{T,Missing}} where T
JuliaCon 2019 | What's Bad About Julia | Jeff Bezanson
https://www.youtube.com/watch?v=TPuJsgyu87U
14:00 ぐらい