Проблема с быстрым полиморфизмом и динамическим типом - PullRequest
0 голосов
/ 19 декабря 2018

Я только что столкнулся со странным поведением в обработке наследования swift, когда речь идет о полиморфизме и динамических типах.В следующем коде показана проблема, с которой я сталкиваюсь. В основном это: Динамический тип распознается правильно (печатается print("type(of: self) = \(classType)")), но универсальная функция testGeneric использует неправильный тип.

class Global {
    static func testGeneric<T: TestSuperClass>(of type: T.Type) {
        print("T.Type = \(T.self)")
    }
}

class TestSuperClass {
    func run() {
        let classType = type(of: self)
        print("type(of: self) = \(classType)")
        Global.testGeneric(of: classType)
    }
}

class TestClass: TestSuperClass {

}

class TestClass2: TestSuperClass {
    override func run() {
        let classType = type(of: self)
        print("type(of: self) = \(classType)")
        Global.testGeneric(of: classType)
    }
}

let testClass = TestClass()
let testClass2 = TestClass2()

testClass.run()
testClass2.run()

напечатанныйвывод

тип (из: self) = TestClass
T.Type = TestSuperClass
тип (из: self) = TestClass2
T.Type = TestClass2

Так что в основном при вызове testClass.run(), type(of: self) выдает TestClass, что я и ожидал.Проблема в том, что обобщенная функция testGeneric, которая вызывается сразу после этого, почему-то не работает с типом TestClass, но вместо этого использует TestSuperClass.

Что я лично ожидаю, так это

тип (из: self) = TestClass
T.Type = TestClass
тип (из: self) = TestClass2
T.Type = TestClass2

т.е. универсальная функция testGeneric, использующая тип TestClass вместо TestSuperClass при вызове через testClass.run().

Вопросы:
- У вас есть объяснениечто?
- Как я могу получить поведение, которое я имел в виду?

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Чтобы ответить на второй вопрос: вы не сможете изменить динамический тип восстановленного массива;он всегда будет [TestSuperClass] - хотя он будет содержать TestClass объектов:

class Global {
    static func testGeneric<T: TestSuperClass>(of type: T.Type) {
        print("T.Type = \(T.self)")
    }
    static func returnObjects<T: TestSuperClass>(of theType: T.Type) -> [T] {
        let newObj = theType.init()
        let newObjType = type(of:newObj)
        print("type(of: newObj) = \(newObjType)")
        return [newObj]
    }
}

class TestSuperClass {
    required init() {
        print ("TestSuperClass.init")
    }

    func run() {
        let classType = type(of: self)
        print("type(of: self) = \(classType)")
        Global.testGeneric(of: classType)
        let array = Global.returnObjects(of: classType)
        let arrayType = type(of:array)
        print("type(of: self) = \(arrayType)")

        print (array)
    }
}

class TestClass: TestSuperClass {
    required init() {
        super.init()
        print("TestClass.init")
    }

}

let testClass = TestClass()
testClass.run()

TestSuperClass.init
TestClass.init
type (of: self) = TestClass
T.Type = TestSuperClass
TestSuperClass.init
TestClass.init
тип (из: newObj) = TestClass
тип (из: self) = массив
[__lldb_expr_21.TestClass]

0 голосов
/ 19 декабря 2018

В Swift компилятор хочет знать в время компиляции , какой универсальный тип "выводить".Следовательно, система типов будет привязана к статическому типу.Не существует такой вещи, как вывод динамического типа .

Поэтому компилятор генерирует следующее (см. Комментарии):

class TestSuperClass {
    func run() {
        let classType = type(of: self)  // static MetaType TestSuperClass.Type
        print("type(of: self) = \(classType)") // dynamic type: TestClass
        Global.testGeneric(of: classType)  // infer to static type, i.e. testGeneric<TestSuperClass>
    }
}

В результате T.self в вашем случае TestSuperClass, потому что это то, что компилятор может видеть:

static func testGeneric<T: TestSuperClass>(of type: T.Type) {
    print("T.Type = \(T.self)")
}

Вам может понадобиться следующее:

static func testGeneric<T: TestSuperClass>(of type: T.Type) {
    print("T.Type = \(type)")
}

Здесь вы печатаете не тип T, а (динамическое) значение параметра type, что в вашем случае составляет TestClass

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...