Подтвердить что ты не робот

Swift - какая разница между метатипом .Type и .self?

Какая разница между метатипом .Type и .self в Swift?

Do .self и .Type вернуть a struct?

Я понимаю, что .self можно использовать для проверки с помощью dynamicType. Как вы используете .Type?

4b9b3361

Ответ 1

Вот быстрый пример:

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 { ... }

Ответ 2

Где это используется?

Если вы пишете/создаете функцию, которая принимает тип, например, UIView.Type, а не экземпляр, например, UIView() тогда вам следует написать T.Type в качестве типа параметра. То, что он ожидает в качестве параметра, может быть: String.self, CustomTableView.self, someOtherClass.self.

Но зачем функции нужен тип?

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

  1. зарегистрировать функцию из таблицы
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")

Обратите внимание, что вы передали CustomTableViewCell.self. Если позже вы попытаетесь удалить из таблицы tableView типа CustomTableViewCell но не зарегистрируете тип CustomTableViewCell то произойдет сбой, потому что tableView не удалил из очереди/не создал ни одного элемента viewview ячейки типа CustomTableViewCell.

  1. функция декодирования из JSONDecoder. Пример по ссылке
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. Если он не может, то выдает ошибку

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

Подробнее о внутренностях и как это работает:

.Тип

Метатип класса, структуры или типа перечисления - это имя этого типа, за которым следует .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)

.self

Вы можете использовать самовыражение 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 по типам. Также смотрите здесь

Ответ 3

Они появляются в разных местах синтаксически.

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

В синтаксическом месте, где вам нужно написать выражение, Something.self является допустимым выражением. Это выражение типа Something.Type, а значение - это вещь ( "объект класса" в случае классов), которая представляет тип Something. Something.Type не является допустимым синтаксисом выражения.