2017-01-29 2 views
1

Я пытаюсь создать структуру класса, которая имеет один класс с общим типом (с ограничением типа), который используется как ограничение общего типа для другого универсального класса. Как только я попытаюсь подклассифицировать класс ограничения первого типа, этот подкласс более не может быть использован для запуска второго родового класса (но отлично работает для первого). Вот упрощенный пример кода:Инициализация неисправностей Вложенные генераторы

class DataClass { 
    var value: Int 
    required init(value: Int) { 
     self.value = value 
    } 
} 

class Thing: DataClass { 
    required init(value: Int) { 
     super.init(value: value) 
    } 
} 

class ThingWrapper<ThingDataType: Thing>: DataClass { 
    var thing: ThingDataType 
    required init(value: Int) { 
     thing = ThingDataType(value: value) 
     super.init(value: value) 
    } 
} 

class ThingWrapperList<ThingWrapperType: ThingWrapper<Thing>>: DataClass { 
    var things: [ThingWrapperType] 
    required init(value: Int) { 
     things = [ThingWrapperType]() 
     super.init(value: value) 
    } 
} 

Они работают отлично:

var thingWrapper = ThingWrapper<Thing>(value: 42) 
var thingWrapperList = ThingWrapperList<ThingWrapper<Thing>>(value: 42) 

Как делает это:

class NewThing: Thing { 
    required init(value: Int) { 
     super.init(value: value) 
    } 
} 

var newThingWrapper = ThingWrapper<NewThing>(value: 42) 

Но это порождает ошибку:

var newThingWrapperList = ThingWrapperList<ThingWrapper<NewThing>>(value: 42) 
Error: 'ThingWrapperList' requires that 'ThingWrapper<NewThing>' inherit from 'ThingWrapper<Thing>' 

So не могу ли я использовать подкласс внутреннего t ype generic constraint? Возможно, я смогу решить это, избавившись от класса ThingWrapper, но я пытался подражать моему JSON-формату, и теперь мне в основном любопытно, что я делаю неправильно.

+0

Я думаю, что вы пришли из java;) - меньше наследования - может быть, больше протоколов. – muescha

+0

, но почему бы не просто простые структуры? – muescha

+0

у вас есть образец вашего json-формата, где вам нужны эти дженерики? – muescha

ответ

1

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

Мы можем попытаться упростить это с помощью еще меньшего примера. Давайте предположим, что мы имеем следующую иерархию классов:

class A1 {} 
class A2: A1 {} 
class B1<T: A1> {} 
class B2<T: A1>: B1<T> {} 

Мы можем исследовать правила Swift навязывает:

// These first 3 assignments compile correctly: 
let a: A1 = A2()   // because A2 inherits from A1 
let b: B1<A1> = B2<A1>() // because B2 inherits from B1 and A1 == A1 
let b2: B1<A2> = B2<A2>() // because B2 inherits from B1 and A2 == A2 

// The next 2 assignments do not compile in current Swift 
// due to the lack of covariant generics 
let b3: B1<A1> = B1<A2>() // cannot convert value of type 'B1<A2>' to specified type 'B1<A1>' 
let b4: B1<A1> = B2<A2>() // cannot convert value of type 'B2<A2>' to specified type 'B1<A1>' 

Чтобы воспроизвести проблему, нам нужно добавить еще один слой, поэтому давайте создадим функцию:

func C<T: A1>(_ arg: B1<T>) {} 

C(B1<A1>()) 
C(B1<A2>()) 
C(B2<A1>()) 
C(B2<A2>()) 

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

В заключение, чтобы выразить свой класс иерархию в Swift, вам нужно добавить еще один общий параметр для ThingWrapperList:

class ThingWrapperList<ThingDataType, ThingWrapperType: ThingWrapper<ThingDataType>>: DataClass 

В этой декларации, ThingWrapperList является общим над ThingWrapperTypeиThingDataType, так что вы можете специализироваться это либо Thing, либо NewThing.

Смежные вопросы