Расширение с общим c, где не вызывается предложение - PullRequest
1 голос
/ 01 мая 2020

Следующий код работает так, как и ожидалось:

protocol Storeable {
    associatedtype Value
    func create(value: Value)
}

struct DefaultStore<V>: Storeable {
    typealias Value = V
    func create(value: V) {
        print("base impl. is called with value type: \(String(describing: V.self))")
    }
}

class Event {
    var title: String = ""
    init(title: String) {
        self.title = title
    }
}

extension DefaultStore where Value: Event {
    func create(value: V) {
        print("event impl. is called with event: \(value.title)")
    }
}

DefaultStore().create(value: Event(title: "Dance Party")) 
// prints "event impl. is called with event: Dance Party"
DefaultStore().create(value: "a string object") 
// prints "base impl. is called with value of type: String"

В основном я вызываю функцию в обобщенном c классе DefaultStore, и компилятор вызывает правильную реализацию в зависимости от базового типа.

Теперь у меня есть сценарий, в котором я хочу точно такую ​​же вещь, за исключением того, что она обернута в другой объект с именем Wrapper:

struct Wrapper<StoreType: Storeable,ValueType> where StoreType.Value == ValueType { 
    let store: StoreType
    func create(value: ValueType) { 
        store.create(value: value)
    }
}

let defaultStore = DefaultStore<Event>()
let wrapper = Wrapper(store: defaultStore)
wrapper.create(value: Event(title: "Düsseldorfer Symphoniker"))
// prints: "base impl. is called with value of type: Event"

Здесь я ожидаю, что расширение для Event вызывается, но вместо этого вызывается базовая реализация. Кто-нибудь знает, что я делаю не так?

-

Обновление:

@ matt предполагал, что может быть проблема времени компиляции: "без оболочки, когда вы говорите DefaultStore().create... Событие Информация может быть прочитана вплоть до параметризованного типа DefaultStore generi c. Но в вашей оболочке сначала создается DefaultStore, поэтому он является общим типом и все. "

I Полагайте, что это не так, потому что вы также можете сначала создать DefaultsStore, и он все еще работает без Обертки. Также компилятор предупреждает меня, если типы не совпадают.

1 Ответ

1 голос
/ 01 мая 2020

Ничего общего с "оболочками".

Вы, кажется, думаете, что расширение where в структуре generi c является своего рода заменой некоторой динамической диспетчеризации c, т.е. мы будем ждать до времени выполнения , посмотрим, что за объект является параметром create на самом деле , и отправим соответственно. Это не так, как это работает. Все должно быть решено во время компиляции . Во время компиляции мы знаем, что вы не вызываете create с событием - вы вызываете его с помощью ValueType. Таким образом, он переходит в create с помощью c V.

Так, например:

struct Wrapper {
    let store: DefaultStore<Event>
    func create(value: Event) {
        store.create(value: value)
    }
}

Это работает так, как вы думаете, потому что мы разоблачаем тот факт, что это событие в отношении DefaultStore в точке вызова create.


Это всего лишь предположение о том, в чем заключается ваша путаница.

Другая возможность состоит в том, что вы можете себе представить, что стандартное c разрешение ValueType каким-то образом «просачивается» до разрешения V, но это тоже не так.

Еще одна возможность - вы можете предположить, что DefaultStore<Event> является подтипом DefaultStore<Storable> или подобным, как если бы была динамическая c диспетчеризация для параметризованных типов, но это не тот случай. Все должно быть полностью известно во время компиляции на сайте вызовов.

...