Возможная ошибка? Я могу создать общий экземпляр игнорируя ограничение
Работая над структурой, основанной на узлах, включая сериализацию и десериализацию, я наткнулся на случай, когда я могу создать экземпляр класса, игнорирующий ограничение типа. Почему я могу создать ZNumericProcessor<String>
внутри ZSum
хотя ZNumericProcessor
определяется как ZNumericProcessor<T: ZNumeric>
где String
не соответствует ZNumeric
? И почему это даже работает, что инициализаторы называются хотя для ZSum
не уверен что T
является ZNumeric
?
Обычно я думал, что даже не могу иметь ограничения на инициализацию ZSum, чтобы заставить его компилироваться.
Второе: если бы у меня не было ограничений в начале ZSum
как я мог сыграть T
так что я могу создать экземпляр ZNumericProcessor
если я уверен, что это ZNumeric
?
Код:
//: Playground - noun: a place where people can play
import UIKit
var str = "Hello, playground"
protocol ZNumeric {
}
extension Double: ZNumeric {
}
class ZInput<T> {
}
class ZNumericProcessor<T: ZNumeric> {
}
class ZNode {
let id: String
var name: String?
required init?<T>(type: T.Type, id: String) {
self.id = id
}
init(name: String?) {
id = NSUUID().UUIDString
}
}
class ZSum: ZNode {
required init?<T: ZNumeric>(type: T.Type, id: String) {
super.init(type: type, id: id)
let p = ZNumericProcessor<T>()
print(p)
if !(T.self is ZNumeric.Type) {
print("could not create ZSum, type is not Numeric")
return nil
}
}
override init(name: String?) {
super.init(name: name)
}
}
class ZFactory {
var nodes: [String: ZNode.Type] = [:]
var types: [String: (type: ZNode.Type, id: String) -> ZNode?] = [:]
func node(node: String, type: String, id: String) -> ZNode? {
let n = nodes[node]
if n == nil {
return nil
}
let t = types[type]
if t == nil {
return nil
}
return t!(type: n!, id: id)
}
func registerNode(name: String, type: ZNode.Type) {
nodes[name] = type
}
func registerType(name: String, processor: (type: ZNode.Type, id: String) -> ZNode?) {
types[name] = processor
}
}
class Serializer {
func node() -> (id: String, node: String, type: String)? {
return nil
}
}
var t = ZFactory()
t.registerNode("ZSum", type: ZSum.self)
t.registerType("Double", processor: { (type: ZNode.Type, id: String) -> ZNode? in return type.init(type: Double.self, id: id) } )
t.registerType("String", processor: { (type: ZNode.Type, id: String) -> ZNode? in return type.init(type: String.self, id: id) } )
var n = t.node("ZSum", type: "Double", id: "ID1")
var m = t.node("ZSum", type: "String", id: "ID2")
Изменить: После прочтения этого: поток Stackru я пытался включить его, но менее строгий инициализатор подкласса не будет вызываться (в ZSum), хотя и предоставляется.
import UIKit
var str = "Hello, playground"
protocol ZNumeric {
}
protocol ZStringRepresentable {
}
extension Double: ZNumeric {
}
class ZInput<T> {
}
class ZNumericProcessor<T: ZNumeric> {
}
class ZNode {
let id: String
var name: String?
required init?<T>(type: T.Type, id: String) {
self.id = id
}
init(name: String?) {
id = NSUUID().UUIDString
}
}
class ZSum: ZNode {
required init?<T>(type: T.Type, id: String) {
super.init(type: type, id: id)
print("called") // Never happens
}
required init?<T: ZNumeric>(type: T.Type, id: String) {
super.init(type: type, id: id)
if !(T.self is ZNumeric.Type) {
print("could not create ZSum, type is not Numeric") // This is called with String
return nil
}
let pp = ZNumericProcessor<T>()
}
override init(name: String?) {
super.init(name: name)
}
}
class ZFactory {
var nodes: [String: ZNode.Type] = [:]
var types: [String: (type: ZNode.Type, id: String) -> ZNode?] = [:]
func node(node: String, type: String, id: String) -> ZNode? {
let n = nodes[node]
if n == nil {
return nil
}
let t = types[type]
if t == nil {
return nil
}
return t!(type: n!, id: id)
}
func registerNode(name: String, type: ZNode.Type) {
nodes[name] = type
}
func registerType(name: String, processor: (type: ZNode.Type, id: String) -> ZNode?) {
types[name] = processor
}
}
class Serializer {
func node() -> (id: String, node: String, type: String)? {
return nil
}
}
var t = ZFactory()
t.registerNode("ZSum", type: ZSum.self)
t.registerType("Double", processor: { (type: ZNode.Type, id: String) -> ZNode? in return type.init(type: Double.self, id: id) } )
t.registerType("String", processor: { (type: ZNode.Type, id: String) -> ZNode? in return type.init(type: String.self, id: id) } )
var n = t.node("ZSum", type: "Double", id: "ID1")
var m = t.node("ZSum", type: "String", id: "ID2")
Редактировать 2: Чем проще версия, тот же эффект, тем более ограничительный инициализатор вызывается даже со строкой, хотя строка не является ZNumeric:
protocol ZNumeric {
}
extension Double: ZNumeric {
}
protocol ZInitializable {
init<T>(type: T.Type)
}
class ZNode: ZInitializable {
required init<T>(type: T.Type) {
}
}
class ZSum: ZNode {
required init<T>(type: T.Type) {
super.init(type: type)
}
required init<T: ZNumeric>(type: T.Type) {
super.init(type: type)
print("ZSum ZNumeric:\(type)") // Is called both with String and Double
}
}
func create(node: ZNode.Type) {
let a = node.init(type: Double.self)
let b = node.init(type: String.self)
}
create(ZSum.self)