Какая разница между метатипом .Type
и .self
в Swift?
Do .self
и .Type
вернуть a struct
?
Я понимаю, что .self
можно использовать для проверки с помощью dynamicType
. Как вы используете .Type
?
Какая разница между метатипом .Type
и .self
в Swift?
Do .self
и .Type
вернуть a struct
?
Я понимаю, что .self
можно использовать для проверки с помощью dynamicType
. Как вы используете .Type
?
Вот быстрый пример:
func printType<T>(of type: T.Type) {
// or you could do "\(T.self)" directly and
// replace 'type' parameter with an underscore
print("\(type)")
}
printType(of: Int.self) // this should print Swift.Int
func printInstanceDescription<T>(of instance: T) {
print("\(instance)")
}
printInstanceDescription(of: 42) // this should print 42
Допустим, каждая сущность представлена двумя вещами:
Тип: # entitiy name #
Метатип: # entity name #.Type
Тип метатипа относится к типу любого типа, включая типы классов, типы структур, типы перечисления и типы протоколов.
Вы можете быстро заметить, что это рекурсивно и может быть с помощью таких типов, как (((T.Type).Type).Type)
и так далее.
.Type
возвращает экземпляр метатипа.
Есть два способа получить экземпляр метатипа:
Вызовите .self
для конкретного типа, такого как Int.self
который создаст статический экземпляр Int.Type
.
Получить экземпляр динамического метатипа из любого экземпляра через type(of: someInstance)
.
Опасная зона:
struct S {}
protocol P {}
print("\(type(of: S.self))") // S.Type
print("\(type(of: S.Type.self))") // S.Type.Type
print("\(type(of: P.self))") // P.Protocol
print("\(type(of: P.Type.self))") // P.Type.Protocol
.Protocol
является еще одним метатипом, который существует только в контексте протоколов. Тем не менее, нет никакого способа, как мы можем выразить, что мы хотим только P.Type
. Это предотвращает работу всех общих алгоритмов с метатипами протоколов и может привести к сбоям во время выполнения.
Для более любопытных людей:
Функция type(of:)
фактически обрабатывается компилятором из-за несоответствия, .Protocol
.
// This implementation is never used, since calls to 'Swift.type(of:)' are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
Где это используется?
Если вы пишете/создаете функцию, которая принимает тип, например, UIView.Type
, а не экземпляр, например, UIView()
тогда вам следует написать T.Type
в качестве типа параметра. То, что он ожидает в качестве параметра, может быть: String.self
, CustomTableView.self
, someOtherClass.self
.
Обычно функция, для которой требуется тип, - это функция, которая создает для вас объекты. Я могу вспомнить два хороших примера:
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Обратите внимание, что вы передали CustomTableViewCell.self
. Если позже вы попытаетесь удалить из таблицы tableView типа CustomTableViewCell
но не зарегистрируете тип CustomTableViewCell
то произойдет сбой, потому что tableView не удалил из очереди/не создал ни одного элемента viewview ячейки типа CustomTableViewCell
.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name)
Обратите внимание, try decoder.decode(GroceryProduct.self, from: json)
. Поскольку вы передали GroceryProduct.self
он знает, что ему нужно создать экземпляр объекта типа GroceryProduct
. Если он не может, то выдает ошибку
Подробнее о внутренностях и как это работает:
Метатип класса, структуры или типа перечисления - это имя этого типа, за которым следует .Type. Метатип типа протокола, а не конкретный тип, который соответствует протоколу во время выполнения, - это имя этого протокола, за которым следует .Protocol. Например, метатипом типа класса
SomeClass
являетсяSomeClass.Type
а метатипом протоколаSomeProtocol
являетсяSomeProtocol.Protocol
.От Apple: тип мета-типа
Под капотом AnyClass
есть
typealias AnyClass = AnyObject.Type // which is why you see T.Type
В основном AnyClass
, где вы видите AnyClass
, Any.Type
, AnyObject.Type
, потому что он нуждается в типе. Очень распространенное место, которое мы видим, это когда мы хотим зарегистрировать класс для нашего tableView, используя register
func.
func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
Если вы не уверены, что означает "Свифт".сделай тогда выше, потом посмотри комментарии отсюда
Вышесказанное также можно записать так:
func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
Вы можете использовать самовыражение postfix для доступа к типу в качестве значения. Например, SomeClass.self возвращает сам SomeClass, а не экземпляр SomeClass. И SomeProtocol.self возвращает сам SomeProtocol, а не экземпляр типа, который соответствует SomeProtocol во время выполнения. Вы можете использовать выражение типа (of :) с экземпляром типа для доступа к динамическим типам экземпляров в качестве значения, как показано в следующем примере:
От Apple: тип мета-типа
Код детской площадки:
Простой пример
struct Something {
var x = 5
}
let a = Something()
type(of:a) == Something.self // true
Тяжелый пример
class BaseClass {
class func printClassName() {
print("BaseClass")
}
}
class SubClass: BaseClass {
override class func printClassName() {
print("SubClass")
}
}
let someInstance: BaseClass = SubClass()
/* | |
compileTime Runtime
| |
To extract, use: .self type(of)
The compile-time type of someInstance is BaseClass,
and the runtime type of someInstance is SubClass */
type(of: someInstance) == SubClass.self // TRUE
type(of: someInstance) == BaseClass.self // FALSE
Я настоятельно рекомендую прочитать документацию Apple по типам. Также смотрите здесь
Они появляются в разных местах синтаксически.
В синтаксическом месте, где вам нужно указать тип, Something.Type
является допустимым типом, соответствующим типу, который является метатипом (который является метаклассом для классов) Something
. Something.self
не является допустимым синтаксисом для типа.
В синтаксическом месте, где вам нужно написать выражение, Something.self
является допустимым выражением. Это выражение типа Something.Type
, а значение - это вещь ( "объект класса" в случае классов), которая представляет тип Something
. Something.Type
не является допустимым синтаксисом выражения.