Поиск…


Синтаксис

  • неизменный MyType; поле; поле; конец
  • тип MyType; поле; поле; конец

замечания

Типы являются ключевыми для работы Юлии. Важной идеей для производительности является стабильность типа , которая возникает, когда возвращаемый тип функции зависит только от типов, а не от значений его аргументов.

Отправка по типам

В Julia вы можете определить несколько методов для каждой функции. Предположим, что мы определяем три метода одной и той же функции:

foo(x) = 1
foo(x::Number) = 2
foo(x::Int) = 3

Когда вы решаете, какой метод использовать (называется диспетчером ), Джулия выбирает более конкретный метод, который соответствует типам аргументов:

julia> foo('one')
1

julia> foo(1.0)
2

julia> foo(1)
3

Это облегчает полиморфизм . Например, мы можем легко создать связанный список , указав два неизменных типа с именем Nil и Cons . Эти имена традиционно используются для описания пустого списка и непустого списка, соответственно.

abstract LinkedList
immutable Nil <: LinkedList end
immutable Cons <: LinkedList
    first
    rest::LinkedList
end

Мы представляем пустой список Nil() и любые другие списки с помощью Cons(first, rest) , где first - это первый элемент связанного списка, а rest - связанный список, состоящий из всех остальных элементов. Например, список [1, 2, 3] будет представлен как

julia> Cons(1, Cons(2, Cons(3, Nil())))
Cons(1,Cons(2,Cons(3,Nil())))

Список пуст?

Предположим, мы хотим расширить функцию стандартного библиотечного isempty , которая работает с множеством различных коллекций:

julia> methods(isempty)
# 29 methods for generic function "isempty":
isempty(v::SimpleVector) at essentials.jl:180
isempty(m::Base.MethodList) at reflection.jl:394
...

Мы можем просто использовать синтаксис функции отправки и определить две дополнительные методы isempty . Так как эта функция из Base модуля, мы должны квалифицировать как Base.isempty для того , чтобы продлить его.

Base.isempty(::Nil) = true
Base.isempty(::Cons) = false

Здесь нам вообще не нужны значения аргументов, чтобы определить, пуст ли список. Просто одного типа достаточно, чтобы вычислить эту информацию. Джулия позволяет нам опускать имена аргументов, сохраняя только аннотацию типа, если нам не нужны их значения.

Мы можем проверить , isempty наши isempty методы:

julia> using Base.Test

julia> @test isempty(Nil())
Test Passed
  Expression: isempty(Nil())

julia> @test !isempty(Cons(1, Cons(2, Cons(3, Nil()))))
Test Passed
  Expression: !(isempty(Cons(1,Cons(2,Cons(3,Nil())))))

и действительно, количество методов для isempty увеличилось на 2 :

julia> methods(isempty)
# 31 methods for generic function "isempty":
isempty(v::SimpleVector) at essentials.jl:180
isempty(m::Base.MethodList) at reflection.jl:394

Ясно, что определение того, является ли связанный список пустым или нет, является тривиальным примером. Но это приводит к чему-то более интересному:

Как долго этот список?

Функция length из стандартной библиотеки дает нам длину коллекции или определенные итерации . Существует множество способов реализации length для связанного списка. В частности, используя while цикл, вероятно , самый быстрый и наиболее эффективно использует память в Джулию. Но преждевременной оптимизации следует избегать, так что давайте предположим, что наш связанный список не должен быть эффективным. Каков самый простой способ написать функцию length ?

Base.length(::Nil) = 0
Base.length(xs::Cons) = 1 + length(xs.rest)

Первое определение прост: пустой список имеет длину 0 . Второе определение также легко читается: чтобы подсчитать длину списка, мы подсчитываем первый элемент, а затем подсчитываем длину остальной части списка. Мы можем проверить этот метод так же , как мы тестировали isempty :

julia> @test length(Nil()) == 0
Test Passed
  Expression: length(Nil()) == 0
   Evaluated: 0 == 0

julia> @test length(Cons(1, Cons(2, Cons(3, Nil())))) == 3
Test Passed
  Expression: length(Cons(1,Cons(2,Cons(3,Nil())))) == 3
   Evaluated: 3 == 3

Следующие шаги

Этот пример игрушек довольно далек от реализации всех функций, которые желательны в связанном списке. Его отсутствует, например, итерационный интерфейс. Тем не менее, это иллюстрирует, как отправка может быть использована для написания короткого и четкого кода.

Неизменяемые типы

Самый простой составной тип - неизменный тип. Экземпляры неизменяемых типов, например кортежи , являются значениями. Их поля не могут быть изменены после их создания. Во многих отношениях неизменяемый тип подобен Tuple с именами для самого типа и для каждого поля.

Типы Singleton

Композитные типы, по определению, содержат ряд более простых типов. В Julia это число может быть нулем; то есть непреложный типа допускается не содержат никаких полей. Это сопоставимо с пустым кортежем () .

Почему это может быть полезно? Такие неизменные типы известны как «одноэлементные типы», поскольку только один из них может когда-либо существовать. Значения таких типов известны как «одиночные значения». Стандартная библиотека Base содержит много таких одноэлементных типов. Вот краткий список:

  • Void , тип nothing . Мы можем проверить, что Void.instance (который является специальным синтаксисом для получения одноэлементного значения одноэлементного типа) действительно nothing .
  • Любой тип мультимедиа, такой как MIME"text/plain" , представляет собой одноэлементный тип с одним экземпляром MIME("text/plain") .
  • Irrational{:π} , Irrational{:e} , Irrational{:φ} и подобные типы являются одноточечными типами, а их одноэлементные экземпляры - иррациональные значения π = 3.1415926535897... и т. Д.
  • Характеристики размера итератора Base.HasLength , Base.HasShape , Base.IsInfinite и Base.SizeUnknown - это все одноэлементные типы.
0.5.0
  • В версии 0.5 и более поздней, каждая функция представляет собой одноэлементный экземпляр одноэлементного типа! Как и любое другое значение singleton, мы можем восстановить функцию sin , например, из typeof(sin).instance .

Поскольку они не содержат ничего, одноэлементные типы невероятно легкие, и их часто можно оптимизировать компилятором, чтобы не иметь накладных расходов во время работы. Таким образом, они идеально подходят для черт, специальных значений тегов и для таких функций, как функции, на которые стоит специализироваться.

Чтобы определить одноэлементный тип,

julia> immutable MySingleton end

Чтобы определить пользовательскую печать для одноэлементного типа,

julia> Base.show(io::IO, ::MySingleton) = print(io, "sing")

Чтобы получить доступ к экземпляру singleton,

julia> MySingleton.instance
MySingleton()

Часто это присваивается константе:

julia> const sing = MySingleton.instance
MySingleton()

Типы оберток

Если неизменяемые типы нулевого поля интересны и полезны, то, возможно, еще более полезны однотипные неизменные типы. Такие типы обычно называют «типами обертки», потому что они обертывают некоторые базовые данные, обеспечивая альтернативный интерфейс к указанным данным. Примером типа оболочки в Base является String . Мы будем определять аналогичный тип для String именем MyString . Этот тип будет поддерживаться векторным (одномерный массив ) байтов ( UInt8 ).

Во-первых, само определение типа и некоторые настройки показывают:

immutable MyString <: AbstractString
    data::Vector{UInt8}
end

function Base.show(io::IO, s::MyString)
    print(io, "MyString: ")
    write(io, s.data)
    return
end

Теперь наш тип MyString готов к использованию! Мы можем прокормить его некоторыми сырыми данными UTF-8, и он отображает, как нам нравится:

julia> MyString([0x48,0x65,0x6c,0x6c,0x6f,0x2c,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21])
MyString: Hello, World!

Очевидно, что этот тип строки требует большой работы, прежде чем он станет таким же удобным, как и тип Base.String .

Истинные составные типы

Возможно, чаще всего многие неизменяемые типы содержат более одного поля. Примером может служить стандартная библиотека Rational{T} type, которая содержит два fieds: поле num для числителя и поле den для знаменателя. Эту модель такого типа довольно просто:

immutable MyRational{T}
    num::T
    den::T
    MyRational(n, d) = (g = gcd(n, d); new(n÷g, d÷g))
end
MyRational{T}(n::T, d::T) = MyRational{T}(n, d)

Мы успешно внедрили конструктор, который упрощает наши рациональные числа:

julia> MyRational(10, 6)
MyRational{Int64}(5,3)


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow