Контейнерные типы и система типов
Подробнее тема раскрыта в главе Типы. Эта глава дает возможность начать работать, отложив теорию на потом.
Функции и Array
Система типов в Julia работает строже с элементами контейнерных типов в качестве параметров функций, чем с элементами простых типов. (У типа Tuple эти правила отличаются). Это свойство всех языков, где типовые параметры функций инвариантны. Это значит, например, тип "массив Int"
не является подтипом "массива Any"
:
julia> typeof([1,2,3])<:Array{Any}
false
хотя Int
- подтип Any
:
typeof(2)<:Any
true
из этого следует, что если вы определите функцию, ожидающую Array{Any}, и думаете, что разрешаете любые массивы для нее, то вы ошибаетесь:
julia> f(a::Array{Any}) = a[1] # кажется, что Array{Any} -это "любой" массив
julia> f([1,2])
ERROR: MethodError: no method matching f(::Array{Int64,1})
Closest candidates are:
f(::Array{Any,N}) at REPL[33]:1
Julia сообщает, что самое похожее, что она нашла на тему функции f
, принимающей массив, так это - f(::Array{Any,N} , а не f(::Array{Int64,1}).
В данном случае можно определить тип так:
julia> f(a::Array) = a[1]
julia> f([2,3]) # проверим
2 # работает
Функции и Dict
Как и в случае с массивами и другими контернейными типами данных, функция, ожидающая Dict{Symbol,AbstractString}
не примет Dict{Symbol,String}
:
f(d::Dict{Symbol,AbstractString}) = d
d1 = Dict{Symbol,String}()
julia> f(d1)
ERROR: MethodError: `f` has no method matching f(::Dict{Symbol,String})
Конструкторы контейнерных типов
Сами контейнерные типы (и их конструкторы) ведут себя мягче.
Dict{Any,Any} позволит хранить непостоянные типы значений:
d["asdf"]=12
d
Dict{Any,Any} with 2 entries:
:a => "asd"
"asdf" => 12
Задать типы значений пустого словаря можно, например, параметризовав его конструктор типами:
d1 = Dict{Symbol,AbstractString}()
При создании словаря через конструктор с начальными значениями, произойдет автоматический вывод типов. Можно инициализировать словарь, например, парой ключ=>значение:
d1 = Dict(:a=>"abc")
julia> Dict{Symbol,String} with 1 entry:
:a => "abc"
В отличие от Dict{Any,Any} этот словарь не даст записать в него другие типы ключей или значений, так: d1[123]="asd" выдаст ошибку.
Однако словарь Dict{Symbol,AbstractString} позволит записать значение конкретного типа String:
d1 = Dict{Symbol,AbstractString}()
Dict{Symbol,AbstractString} with 0 entries
julia> d1[:a]=String("asd")
"asd"
julia> d1
Dict{Symbol,AbstractString} with 1 entry:
:a => "asd"
Это был беглый обзор часто встречающихся подводных камней для нетерпеливых.