Возможная ошибка? Я могу создать общий экземпляр игнорируя ограничение

Работая над структурой, основанной на узлах, включая сериализацию и десериализацию, я наткнулся на случай, когда я могу создать экземпляр класса, игнорирующий ограничение типа. Почему я могу создать 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)

0 ответов

Другие вопросы по тегам