Spec-Zone.ru › Swift Language

Типы

Используйте встроенные именованные и составные типы.

В Swift есть два типа типов: именованные и составные. Именованный тип — это тип, которому можно присвоить определённое имя при его определении. К именованным типам относятся классы, структуры, перечисления и протоколы. Например, экземпляры пользовательского класса, названного MyClass, имеют тип MyClass. Помимо определяемых пользователем именованных типов, стандартная библиотека Swift определяет многие часто используемые именованные типы, включая те, что представляют массивы, словари и значения-опционалы.

Типы данных, которые обычно считаются базовыми или примитивными в других языках — такие как типы, представляющие числа, символы и строки — на самом деле являются именованными типами, определёнными и реализованными в стандартной библиотеке Swift с помощью структур. Поскольку это именованные типы, вы можете расширить их поведение, чтобы оно соответствовало потребностям вашей программы, используя объявление расширения, о котором рассказывается в Расширениях и <doc:Declarations#Extension-Declaration>.

Составной тип — это тип без имени, определённый в самом языке Swift. Есть два составных типа: типы функций и типы кортежей. Составной тип может содержать именованные типы и другие составные типы. Например, тип кортежа (Int, (Int, Int)) содержит два элемента: первый — именованный тип Int, а второй — другой составной тип (Int, Int).

Вы можете поместить скобки вокруг именованного типа или составного типа. Однако добавление скобок вокруг типа не оказывает никакого влияния. Например, (Int) эквивалентно Int.

В этой главе рассматриваются типы, определённые в самом языке Swift, и описывается поведение вывода типа в Swift.

Грамматика типа:

type → function-type
type → array-type
type → dictionary-type
type → type-identifier
type → tuple-type
type → optional-type
type → implicitly-unwrapped-optional-type
type → protocol-composition-type
type → opaque-type
type → boxed-protocol-type
type → metatype-type
type → any-type
type → self-type
type → ( type )

Аннотация типа

Аннотация типа явно указывает тип переменной или выражения. Аннотации типов начинаются с двоеточия (:) и заканчиваются типом, как показано в следующих примерах:

let someTuple: (Double, Double) = (3.14159, 2.71828)
func someFunction(a: Int) { /* ... */ }

В первом примере выражение someTuple указано как имеющее тип кортежа (Double, Double). Во втором примере параметр a функции someFunction указан как имеющий тип Int.

Аннотации типов могут содержать необязательный список атрибутов типа перед типом.

Грамматика аннотации типа:

type-annotation → : attributes_?_ type

Идентификатор типа

Идентификатор типа относится либо к именованному типу, либо к псевдониму типа именованного или составного типа.

Большую часть времени идентификатор типа непосредственно ссылается на именованный тип с тем же именем, что и идентификатор. Например, Int — это идентификатор типа, который напрямую ссылается на именованный тип Int, а идентификатор типа Dictionary<String, Int> напрямую ссылается на именованный тип Dictionary<String, Int>.

Есть два случая, когда идентификатор типа не ссылается на тип с тем же именем. В первом случае идентификатор типа ссылается на псевдоним типа именованного или составного типа. Например, в примере ниже использование Point в аннотации типа относится к типу кортежа (Int, Int).

typealias Point = (Int, Int)
let origin: Point = (0, 0)

Во втором случае идентификатор типа использует синтаксис точки (.) для ссылки на именованные типы, объявленные в других модулях или вложенные в другие типы. Например, идентификатор типа в следующем коде ссылается на именованный тип MyType, объявленный в модуле ExampleModule.

var someValue: ExampleModule.MyType

Грамматика идентификатора типа:

type-identifier → type-name generic-argument-clause_?_ | type-name generic-argument-clause_?_ . type-identifier
type-name → identifier

Тип кортежа

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

Вы можете использовать тип кортежа в качестве возвращаемого типа функции, чтобы функция могла возвращать один кортеж, содержащий несколько значений. Вы также можете присвоить имена элементам типа кортежа и использовать эти имена для ссылки на значения отдельных элементов. Имя элемента состоит из идентификатора, за которым сразу следует двоеточие (:). Пример, демонстрирующий оба этих аспекта, см. в <doc:Functions#Functions-with-Multiple-Return-Values>.

Когда у элемента типа кортежа есть имя, это имя является частью типа.

var someTuple = (top: 10, bottom: 12)  // someTuple is of type (top: Int, bottom: Int)
someTuple = (top: 4, bottom: 42) // OK: names match
someTuple = (9, 99)              // OK: names are inferred
someTuple = (left: 5, right: 5)  // Error: names don't match

Все типы кортежей содержат два или более типа, за исключением Void, который является псевдонимом для пустого типа кортежа ().

Грамматика типа кортежа:

tuple-type → ( ) | ( tuple-type-element , tuple-type-element-list )
tuple-type-element-list → tuple-type-element | tuple-type-element , tuple-type-element-list
tuple-type-element → element-name type-annotation | type
element-name → identifier

Тип функции

Тип функции представляет тип функции, метода или замыкания и состоит из параметра и возвращаемого типа, разделённых стрелкой (->):

(<#parameter type#>) -> <#return type#>

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

Параметр типа функции () -> T (где T — любой тип) может применять атрибут autoclosure, чтобы неявно создать замыкание в местах его вызова. Это обеспечивает синтаксически удобный способ отложить оценку выражения без необходимости написания явного замыкания при вызове функции. Пример функции с параметром-автозамыканием см. в <doc:Closures#Autoclosures>.

Тип функции может иметь параметры-переменной длины в его типе параметра. Синтаксически параметр-переменной длины состоит из имени базового типа, за которым сразу следуют три точки (...), как в Int.... Параметр-переменной длины обрабатывается как массив, который содержит элементы имени базового типа. Например, параметр-переменной длины Int... обрабатывается как [Int]. Пример использования параметра-переменной длины см. в <doc:Functions#Variadic-Parameters>.

Для указания параметра-входа префикс типа параметра должен иметь ключевое слово inout. Нельзя пометить параметр-переменной длины или возвращаемый тип ключевым словом inout. Параметры-входы обсуждаются в <doc:Functions#In-Out-Parameters>.

Если тип функции имеет только один параметр, а тип этого параметра — тип кортежа, то тип кортежа должен быть заключён в скобки при написании типа функции. Например, ((Int, Int)) -> Void — это тип функции, которая принимает один параметр типа кортежа (Int, Int) и ничего не возвращает. В противоположность этому, без скобок (Int, Int) -> Void — это тип функции, которая принимает два Int параметра и ничего не возвращает. Аналогично, поскольку Void — это псевдоним для (), тип функции (Void) -> Void такой же, как (()) -> () — функция, которая принимает один аргумент, который является пустым кортежем. Эти типы не такие же, как () -> () — функция, которая не принимает аргументов.

Имена аргументов в функциях и методах не являются частью соответствующего типа функции. Например:

func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}

var f = someFunction // The type of f is (Int, Int) -> Void, not (left: Int, right: Int) -> Void.
f = anotherFunction              // OK
f = functionWithDifferentLabels  // OK

func functionWithDifferentArgumentTypes(left: Int, right: String) {}
f = functionWithDifferentArgumentTypes     // Error

func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentNumberOfArguments // Error

Поскольку имена меток аргументов не входят в тип функции, вы их опускаете при написании типа функции.

var operation: (lhs: Int, rhs: Int) -> Int     // Error
var operation: (_ lhs: Int, _ rhs: Int) -> Int // OK
var operation: (Int, Int) -> Int               // OK

Если тип функции включает более одной стрелки (->), типы функций группируются справа налево. Например, тип функции (Int) -> (Int) -> Int понимается как (Int) -> ((Int) -> Int) — то есть функция, которая принимает Int и возвращает другую функцию, которая принимает и возвращает Int.

Типы функций для функций, которые могут генерировать или повторно генерировать ошибку, должны включать ключевое слово throws. Вы можете включить тип после throws в скобках, чтобы указать тип ошибки, которую генерирует функция. Тип ошибки должен соответствовать протоколу Error. Написание throws без указания типа эквивалентно написанию throws(any Error). Пропуск throws эквивалентен написанию throws(Never). Тип ошибки, который генерирует функция, может быть любым типом, соответствующим Error, включая обобщённые типы, упакованные протоколы и неявные типы.

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

  1. Функции, генерирующие любую ошибку, помеченные throws(any Error)
  2. Функции, генерирующие определённую ошибку, помеченные throws(MyError)
  3. Функции, которые не генерируют ошибку, помеченные throws(Never)

В результате этих отношений подтипов:

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

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

Функции с ошибками и повторно генерирующие ошибки описаны в <doc:Declarations#Throwing-Functions-and-Methods> и <doc:Declarations#Rethrowing-Functions-and-Methods>.

END_OF_DOCUMENT_MARKER

Типы функций для асинхронных функций должны быть помечены ключевым словом async. Ключевое слово async является частью типа функции, а синхронные функции являются подтипами асинхронных функций. В результате вы можете использовать синхронную функцию в тех же местах, что и асинхронную. Дополнительную информацию об асинхронных функциях см. в <doc:Объявления#Асинхронные-функции-и-методы>.

Ограничения для замыканий, не выходящих за пределы области видимости

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

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

let external: (() -> Void) -> Void = { _ in () }
func takesTwoFunctions(first: (() -> Void) -> Void, second: (() -> Void) -> Void) {
    first { first {} }       // Error
    second { second {}  }    // Error

    first { second {} }      // Error
    second { first {} }      // Error

    first { external {} }    // OK
    external { first {} }    // OK
}

В приведенном выше коде оба параметра для takesTwoFunctions(first:second:) являются функциями. Ни один из параметров не помечен @escaping, поэтому оба являются функциями, не выходящими за пределы области видимости.

Четыре вызова функций, помеченные «Ошибка» в примере выше, вызывают ошибки компилятора. Поскольку параметры first и second являются функциями, не выходящими за пределы области видимости, их нельзя передавать в качестве аргументов другому параметру функции, не выходящей за пределы области видимости. В отличие от этого, два вызова функций, помеченные «ОК», не вызывают ошибки компилятора. Эти вызовы функций не нарушают ограничение, потому что external не является одним из параметров takesTwoFunctions(first:second:).

Если вам нужно обойти это ограничение, отметьте один из параметров как «выходящий за пределы области видимости» или временно преобразуйте один из параметров функции, не выходящей за пределы области видимости, в функцию, выходящую за пределы области видимости, используя функцию withoutActuallyEscaping(_:do:). Дополнительную информацию об избежании конфликтующего доступа к памяти см. в MemorySafety.

Грамматика типа функции:

function-type → attributes_?_ function-type-argument-clause async_?_ throws-clause_?_ -> type

function-type-argument-clause → ( )
function-type-argument-clause → ( function-type-argument-list ..._?_ )

function-type-argument-list → function-type-argument | function-type-argument , function-type-argument-list
function-type-argument → attributes_?_ parameter-modifier_?_ type | argument-label type-annotation
argument-label → identifier

throws-clause → throws | throws ( type )

Тип массива

Язык Swift предоставляет следующий синтаксический сахар для типа стандартной библиотеки Swift Array<Element>:

[<#type#>]

Другими словами, следующие два объявления эквивалентны:

let someArray: Array<String> = ["Alex", "Brian", "Dave"]
let someArray: [String] = ["Alex", "Brian", "Dave"]

В обоих случаях константа someArray объявляется как массив строк. Элементы массива можно получить по индексу, указав допустимое значение индекса в квадратных скобках: someArray[0] относится к элементу с индексом 0, "Alex".

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

var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

При доступе к элементам многомерного массива индекс левого подстрочного индекса относится к элементу в этом индексе во внешнем массиве. Следующий подстрочный индекс справа относится к элементу в массиве, вложенном на один уровень внутрь. И так далее. Это означает, что в приведенном выше примере array3D[0] относится к [[1, 2], [3, 4]], array3D[0][1] относится к [3, 4], а array3D[0][1][1] относится к значению 4.

Подробное обсуждение типа стандартной библиотеки Swift Array см. в <doc:Типы-коллекций#Массивы>.

Грамматика типа массива:

array-type → [ type ]

Тип словаря

Язык Swift предоставляет следующий синтаксический сахар для типа стандартной библиотеки Swift Dictionary<Key, Value>:

[<#key type#>: <#value type#>]

Другими словами, следующие два объявления эквивалентны:

let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]

В обоих случаях константа someDictionary объявляется как словарь со строками в качестве ключей и целыми числами в качестве значений.

Значения словаря можно получить по индексу, указав соответствующий ключ в квадратных скобках: someDictionary["Alex"] относится к значению, связанному с ключом "Alex". Подстрочный индекс возвращает значение типа значения словаря в виде необязательного значения. Если указанный ключ не содержится в словаре, подстрочный индекс возвращает nil.

Тип ключа словаря должен соответствовать протоколу стандартной библиотеки Swift Hashable.

Подробное обсуждение типа стандартной библиотеки Swift Dictionary см. в <doc:Типы-коллекций#Словари>.

Грамматика типа словаря:

dictionary-type → [ type : type ]

Тип необязательного значения

Язык Swift определяет постфикс ? как синтаксический сахар для именованного типа Optional<Wrapped>, который определен в стандартной библиотеке Swift. Другими словами, следующие два объявления эквивалентны:

var optionalInteger: Int?
var optionalInteger: Optional<Int>

В обоих случаях переменная optionalInteger объявляется как тип необязательного целого числа. Обратите внимание, что пробелы между типом и ? не допускаются.

Тип Optional<Wrapped> — это перечисление с двумя случаями, none и some(Wrapped), которые используются для представления значений, которые могут или не могут присутствовать. Любой тип может быть явно объявлен как (или неявно преобразован в) тип необязательного значения. Если при объявлении необязательной переменной или свойства вы не задаете начальное значение, его значение по умолчанию автоматически устанавливается в nil.

Если экземпляр типа необязательного значения содержит значение, вы можете получить доступ к этому значению с помощью постфиксного оператора !, как показано ниже:

optionalInteger = 42
optionalInteger! // 42

Использование оператора ! для распаковки необязательного значения, имеющего значение nil, приводит к ошибке во время выполнения.

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

Дополнительную информацию и примеры использования типов необязательных значений см. в <doc:Основы#Необязательные-значения>.

Грамматика типа необязательного значения:

optional-type → type ?

Тип неявно распакованного необязательного значения

Язык Swift определяет постфикс ! как синтаксический сахар для именованного типа Optional<Wrapped>, который определен в стандартной библиотеке Swift, с дополнительным поведением автоматического распаковки при обращении. Если вы попытаетесь использовать неявно распакованное необязательное значение, имеющее значение nil, произойдет ошибка во время выполнения. За исключением поведения неявной распаковки, следующие два объявления эквивалентны:

var implicitlyUnwrappedString: String!
var explicitlyUnwrappedString: Optional<String>

Обратите внимание, что пробелы между типом и ! не допускаются.

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

let tupleOfImplicitlyUnwrappedElements: (Int!, Int!)  // Error
let implicitlyUnwrappedTuple: (Int, Int)!             // OK

let arrayOfImplicitlyUnwrappedElements: [Int!]        // Error
let implicitlyUnwrappedArray: [Int]!                  // OK

Поскольку неявно распакованные необязательные значения имеют тот же Optional<Wrapped> тип, что и необязательные значения, вы можете использовать неявно распакованные необязательные значения во всех тех же местах в своем коде, где вы можете использовать необязательные значения. Например, вы можете присваивать значения неявно распакованных необязательных значений переменным, константам и свойствам необязательных значений и наоборот.

Как и в случае с необязательными значениями, если вы не задаете начальное значение при объявлении неявно распакованной необязательной переменной или свойства, его значение по умолчанию автоматически устанавливается в nil.

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

Дополнительную информацию о типах неявно распакованных необязательных значений см. в <doc:Основы#Неявно-распакованные-необязательные-значения>.

Грамматика типа неявно распакованного необязательного значения:

implicitly-unwrapped-optional-type → type !

Тип композиции протоколов

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

Типы композиции протоколов имеют следующий вид:

<#Protocol 1#> & <#Protocol 2#>

Тип композиции протоколов позволяет указать значение, тип которого соответствует требованиям нескольких протоколов, без явного определения нового именованного протокола, который наследует от каждого протокола, к которому вы хотите, чтобы тип соответствовал. Например, вы можете использовать тип композиции протоколов ProtocolA & ProtocolB & ProtocolC вместо объявления нового протокола, который наследует от ProtocolA, ProtocolB и ProtocolC. Аналогично, вы можете использовать SuperClass & ProtocolA вместо объявления нового протокола, который является подклассом SuperClass и соответствует ProtocolA.

Каждый элемент в списке композиции протоколов — это один из следующих; список может содержать не более одного класса:

  • Имя класса
  • Имя протокола
  • Псевдоним типа, основой которого является тип композиции протоколов, протокол или класс.

Когда тип композиции протоколов содержит псевдонимы типов, возможно, что один и тот же протокол появится более чем один раз в определениях — дубликаты игнорируются. Например, определение PQR в коде ниже эквивалентно P & Q & R.

typealias PQ = P & Q
typealias PQR = PQ & Q & R

Грамматика типа композиции протоколов:

protocol-composition-type → type-identifier & protocol-composition-continuation
protocol-composition-continuation → type-identifier | protocol-composition-type

Непрозрачный тип

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

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

Непрозрачные типы имеют следующий вид:

some <#constraint#>

Ограничение — это тип класса, тип протокола, тип композиции протоколов или Any. Значение может быть использовано в качестве экземпляра непрозрачного типа только в том случае, если это экземпляр типа, который соответствует перечисленному протоколу или композиции протоколов, или наследует от указанного класса. Код, который взаимодействует со значением непрозрачного типа, может использовать это значение только способами, которые являются частью интерфейса, определенного ограничением.

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

Объявления протоколов не могут включать непрозрачные типы. Классы не могут использовать непрозрачный тип в качестве типа возврата нефинального метода.

Функция, использующая непрозрачный тип в качестве типа возврата, должна возвращать значения, которые имеют один и тот же базовый тип. Тип возврата может включать типы, которые являются частью дженерик-параметров функции. Например, функция someFunction<T>() может возвращать значение типа T или Dictionary<String, T>.

Грамматика непрозрачного типа:

opaque-type → some type

Упакованный тип протокола

Упакованный тип протокола определяет тип, который соответствует протоколу или композиции протоколов, с возможностью изменения этого соответствующего типа во время выполнения программы.

Упакованные типы протоколов имеют следующий вид:

any <#constraint#>

Ограничение — это тип протокола, тип композиции протоколов, метатип типа протокола или метатип композиции протоколов.

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

Применение any к типам Any или AnyObject не оказывает никакого влияния, потому что эти типы уже являются упакованными типами протоколов.

Грамматика упакованного типа протокола:

boxed-protocol-type → any type

Тип метатипа

Тип метатипа относится к типу любого типа, включая типы классов, типы структур, типы перечислений и типы протоколов.

Метатип типа класса, структуры или перечисления — это имя этого типа, за которым следует .Type. Метатип типа протокола — не конкретный тип, который соответствует протоколу во время выполнения — это имя этого протокола, за которым следует .Protocol. Например, метатип типа класса SomeClass — это SomeClass.Type, а метатип протокола SomeProtocol — это SomeProtocol.Protocol.

Можно использовать постфиксное выражение self, чтобы получить доступ к типу как к значению. Например, SomeClass.self возвращает сам SomeClass, а не экземпляр SomeClass. И SomeProtocol.self возвращает сам SomeProtocol, а не экземпляр типа, который соответствует SomeProtocol во время выполнения. Можно вызвать функцию type(of:) с экземпляром типа, чтобы получить доступ к динамическому типу этого экземпляра во время выполнения как к значению, как показано в следующем примере:

class SomeBaseClass {
    class func printClassName() {
        print("SomeBaseClass")
    }
}
class SomeSubClass: SomeBaseClass {
    override class func printClassName() {
        print("SomeSubClass")
    }
}
let someInstance: SomeBaseClass = SomeSubClass()
// The compile-time type of someInstance is SomeBaseClass,
// and the runtime type of someInstance is SomeSubClass
type(of: someInstance).printClassName()
// Prints "SomeSubClass"

Дополнительную информацию см. в type(of:) в стандартной библиотеке Swift.

Используйте выражение инициализатора для создания экземпляра типа из значения метатипа этого типа. Для экземпляров классов вызываемый инициализатор должен быть помечен ключевым словом required или весь класс должен быть помечен ключевым словом final.

class AnotherSubClass: SomeBaseClass {
    let string: String
    required init(string: String) {
        self.string = string
    }
    override class func printClassName() {
        print("AnotherSubClass")
    }
}
let metatype: AnotherSubClass.Type = AnotherSubClass.self
let anotherInstance = metatype.init(string: "some string")

Грамматика типа метатипа:

metatype-type → type . Type | type . Protocol

Тип Any

Тип Any может содержать значения всех других типов. Any может быть использован в качестве конкретного типа для экземпляра любого из следующих типов:

  • Класс, структура или перечисление
  • Метатип, например Int.self
  • Кортеж с любыми типами компонентов
  • Замыкание или тип функции
let mixed: [Any] = ["one", 2, true, (4, 5.3), { () -> Int in return 6 }]

Когда вы используете Any в качестве конкретного типа для экземпляра, вам необходимо привести экземпляр к известному типу, прежде чем вы сможете получить доступ к его свойствам или методам. Экземпляры с конкретным типом Any сохраняют свой исходный динамический тип и могут быть приведены к этому типу с помощью одного из операторов приведения типов — as, as? или as!. Например, используйте as? для условного приведения первого объекта в неоднородном массиве к типу String следующим образом:

if let first = mixed.first as? String {
    print("The first item, '\(first)', is a string.")
}
// Prints "The first item, 'one', is a string."

Дополнительную информацию о приведении типов см. в Приведение типов.

Протокол AnyObject похож на тип Any. Все классы неявно соответствуют протоколу AnyObject. В отличие от Any, который определен языком, AnyObject определен стандартной библиотекой Swift. Дополнительную информацию см. в <doc:Protocols#Class-Only-Protocols> и AnyObject.

Грамматика типа Any:

any-type → Any

Тип Self

Тип Self — это не конкретный тип, а удобный способ сослаться на текущий тип без повторения или знания имени этого типа.

В объявлении протокола или объявлении члена протокола тип Self относится к будущему типу, который соответствует протоколу.

В объявлении структуры, класса или перечисления тип Self относится к типу, введенному объявлением. Внутри объявления члена типа тип Self относится к этому типу. В членах объявления класса Self может появляться только следующим образом:

  • В качестве типа возвращаемого значения метода
  • В качестве типа возвращаемого значения только для чтения подстроки
  • В качестве типа только для чтения вычисляемого свойства
  • В теле метода

Например, код ниже показывает метод экземпляра f, тип возвращаемого значения которого является Self.

class Superclass {
    func f() -> Self { return self }
}
let x = Superclass()
print(type(of: x.f()))
// Prints "Superclass"

class Subclass: Superclass { }
let y = Subclass()
print(type(of: y.f()))
// Prints "Subclass"

let z: Superclass = Subclass()
print(type(of: z.f()))
// Prints "Subclass"

Последняя часть примера выше показывает, что Self относится к типу во время выполнения Subclass значения z, а не к типу во время компиляции Superclass самой переменной.

Внутри объявления вложенного типа тип Self относится к типу, введенному самым внутренним объявлением типа.

Тип Self относится к тому же типу, что и функция type(of:) в стандартной библиотеке Swift. Написание Self.someStaticMember для доступа к члену текущего типа эквивалентно написанию type(of: self).someStaticMember.

Грамматика типа Self:

self-type → Self

Определение наследования типов

Определение наследования типов используется для указания, от какого класса наследуется именованный тип, и каким протоколам он соответствует. Определение наследования типов начинается с двоеточия (:), за которым следует список идентификаторов типов.

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

Другие именованные типы могут только наследоваться от или соответствовать списку протоколов. Типы протоколов могут наследоваться от любого количества других протоколов. Когда тип протокола наследуется от других протоколов, набор требований из этих других протоколов объединяется, и любой тип, который наследуется от текущего протокола, должен соответствовать всем этим требованиям.

Определение наследования типов в определении перечисления может быть либо списком протоколов, либо, в случае перечисления, которое присваивает значения по умолчанию его случаям, одним именованным типом, который определяет тип этих значений по умолчанию. Пример определения перечисления, которое использует определение наследования типов для указания типа его значений по умолчанию, см. в <doc:Enumerations#Raw-Values>.

Грамматика определения наследования типов:

type-inheritance-clause → : type-inheritance-list
type-inheritance-list → attributes_?_ type-identifier | attributes_?_ type-identifier , type-inheritance-list

Вывод типов

Swift использует вывод типов очень широко, позволяя вам опустить тип или часть типа многих переменных и выражений в вашем коде. Например, вместо того, чтобы писать var x: Int = 0, вы можете написать var x = 0, полностью опустив тип — компилятор правильно выводит, что x обозначает значение типа Int. Аналогично, вы можете опустить часть типа, когда полный тип может быть выведен из контекста. Например, если вы напишете let dict: Dictionary = ["A": 1], компилятор выведет, что dict имеет тип Dictionary<String, Int>.

В обоих примерах информация о типе передаётся сверху вниз от листьев дерева выражения к его корню. То есть, тип x в var x: Int = 0 выводится, сначала проверяя тип 0, а затем передавая эту информацию о типе вверх к корню (переменной x).

В Swift информация о типе также может передаваться в обратном направлении — от корня к листьям. Например, в следующем примере явное указание типа (: Float) для константы eFloat заставляет числовую литерал 2.71828 иметь выведенный тип Float вместо Double.

let e = 2.71828 // The type of e is inferred to be Double.
let eFloat: Float = 2.71828 // The type of eFloat is Float.

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

This source file is part of the Swift.org open source project
Copyright © 2014 - 2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API