Почему я получаю сообщение об ошибке "Протокол… может использоваться только как общее ограничение, потому что он имеет Self или требования к связанному типу"?
Я написал расширение на Int
как ниже.
extension Int {
func squared () -> Int {
return self * self
}
}
print(10.squared()) // works
Приведенный выше код работает. Теперь я хочу продлить IntegerType
протокол, так что Int, UInt, Int64 и т. д. будет соответствовать. Мой код, как показано ниже.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
Я получаю ошибку:
Протокол 'IntegerType' может использоваться только в качестве общего ограничения, потому что он имеет Self или требования к связанному типу.
Я уже видел этот вопрос и его видео и этот вопрос, все еще не мог понять. Я только понял, что есть некоторые associatedType
который в этом случае Self
но не смог соединить точки. Я чувствую, как и мое отсутствие знаний о Generics
предмет тоже причина...
Может кто-нибудь немного рассказать об этом и почему расширение создает ошибку?
2 ответа
Тип возврата функции может быть только конкретным Type
,
Дело в типе. Все структуры, классы или протоколы, которые полностью определены сами по себе, являются чистыми типами. Однако, когда протокол или структура зависят от другого заполнителя универсального типа, такого как T, тогда это частичный тип.
Тип - это конструкция данных, которую компилятор должен выделить определенной памяти.
Так что-то вроде этого:
let a = Array<T>()
или же let b = T
недостаточно информации для вывода компилятором во время компиляции.
Следовательно, это не будет работать.
extension IntegerType {
func squared () -> IntegerType { // this line creates error
return self * self
}
}
Здесь IntegerType является частичным типом. Это общий протокол, который только после согласования может знать точный тип. Похоже на массив. Сам массив не является типом. Это универсальный контейнер. Только когда кто-то создает его с помощью Array() или Array()... тогда он имеет тип.
То же самое случилось с вами.
public protocol IntegerType : _IntegerType, RandomAccessIndexType {
тогда снова,
public protocol RandomAccessIndexType : BidirectionalIndexType, Strideable, _RandomAccessAmbiguity {
@warn_unused_result
public func advancedBy(n: Self.Distance) -> Self
тогда снова,
public protocol _RandomAccessAmbiguity {
associatedtype Distance : _SignedIntegerType = Int
}
Следовательно, так как RandomAccessIndexType имеет значение Self, то есть до тех пор, пока кто-либо не будет ему соответствовать, Self является неизвестным заполнителем. Это частичный тип.
Поскольку IntegerType соответствует типам RandomAccessIndexType и _RandomAccessAmbuiguity, для которых также требуется связанный тип Distance.
Следовательно, вы не можете сделать это тоже
let a: IntegerType = 12
Опять же, IntegerType необходимо знать Self и Distance (relatedType).
Int, однако, предоставляет такие детали, как так
public struct Int : SignedIntegerType, Comparable, Equatable {
/// A type that can represent the number of steps between pairs of
/// values.
public typealias Distance = Int
Следовательно, вы можете сделать такое
let a:Int = 10
потому что он предоставляет Self для SignedIntegerType и Distance для своего другого аналога.
Проще говоря:
Частичный тип не может использоваться там, где может быть конкретный тип. Частичный тип хорош для других обобщений и их ограничения.
Вы просто должны вернуться Self
редактировать / обновление:
Примечание. Вы можете расширить все числовые типы (Integer и FloatingPoint) в Swift 4, расширяя числовой протокол.
Swift 4
extension Numeric {
func squared() -> Self {
return self * self
}
}
Свифт 3
extension Integer {
func squared() -> Self {
return self * self
}
}