无法将类实例分配给其协议types?

请参阅下面的例子。 编译器在最后一行报告错误(由COMPILE ERROR标记),我将SimpleTrain一个实例分配给一个协议types(按我的最佳判断)符合。 我怎样才能编译? 我究竟做错了什么? 或者是这个编译器问题?

 protocol Train { typealias CarriageType func addCarriage(carriage: CarriageType) func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType } class SimpleTrain<T> : Train { typealias CarriageType = T private var carriages: [T] = [T]() func addCarriage(carriage: T) { carriages.append(carriage) } func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType { let short = SimpleTrain<T>() short.addCarriage(carriages[0]) return short //COMPILE ERROR: SimpleTrain<T> is not convertible to 'ShortType' } } 

编辑:即使当我明确downcast shortTrain的上面的返回types(以便上面的代码片段的最后一行读取return short as ShortType ) 由安东尼奥build议仍然有调用函数shortTrain时编译错误:

 let s = SimpleTrain<String>() s.addCarriage("Carriage 1") s.addCarriage("Carriage 2") let a = s.shortTrain() //ERROR: Cannot convert the expression's type '()' to type 'Train' let b = s.shortTrain<SimpleTrain<String>>() //ERROR: cannot explicitly specialize a generic function 

首先,你想从devforums读取这个规范的线程 。 你特别想跳过来读jckarter的评论。

现在到编辑的问题:

 let a = s.shortTrain() //ERROR: Cannot convert the expression's type '()' to type 'Train' 

这是因为你没有给编译器足够的信息来确定一个types。 想想看到的是什么:

 func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType { let a = s.shortTrain() 

编译器需要在编译时计算出types,并且不能处理抽象types。 它需要一个完全指定的ShortTypetypes(所有的指定,所有的types别名解决)。 它环顾四周,它看到ShortType一些限制,但它没有看到任何实际给出的types。 它只有a ,而不是任何暗示。

所以不幸的是,你不得不明确地告诉它你想要发生什么。

 let a: SimpleTrain<String> = s.shortTrain() 

这可能与你所要做的相反,但是现在你可以在Swift中完成所有的工作。 Swift团队多次表示,他们很清楚与相关types(以及types系统中的其他一些相关弱点)有关的这些问题。 他们特别意识到可以处理这些事情的Scalatypes系统,并且与当前的Swifttypes系统有很多共同之处(尽pipe根据我的经验,在Scala中获取复杂的path相关的关联types也会导致头发撕裂)。

也就是说,从你的例子来看,你计划用这个function做什么并不明显。 有些火车会返回一个不同的types作为他们的shortTrain()?

我发现这些问题在一般情况下经常会爆炸,但在面前的应用程序的特定情况下往往是相当可以解决的。 很难在Swift中构build真正的任意types的代码来解决所有问题,但是当你专注于你真正需要的types时,经常会遇到这种问题。 例如,如果shortTrain()返回Self ,这显然变得更简单。 如果调用者知道所需的结果types,那么init(shorten:)就可能处理它。 像shortCarriages() -> [CarriageType]这样的协议方法可以提供一个很好的桥梁。 保持灵活的devise,其中一个几乎肯定会解决。

variables的明确倒置:

 let short = SimpleTrain<T>() as ShortType 

或返回值:

 return short as ShortType 

解决了这个问题。

更新

当我回答这个问题的时候,我自己想知道如何使用Train协议作为返回types,是否被分类。

看看这个代码:

 protocol ProtocolWithNoAlias { } protocol ProtocolWithAlias { typealias AliasType } var x: ProtocolWithNoAlias? var y: ProtocolWithAlias? 

最后一行报告为编译错误:

 Protocol 'ProtocolWithAlias' can only be used as a generic constraint because it has Self os associated type requirements 

这意味着您不能使用ProtocolWithAlias作为具体types,这意味着您不能声明具有ProtocolWithAliastypes的variables,因此定义返回它的函数是没有意义的。

在官方文档中我找不到任何提及,但我确定我在某处读过,我只是不记得在哪里。

结论:我解释你遇到的错误:

 SimpleTrain<T> is not convertible to 'ShortType' 

作为协议的直接后果是被分类。

请注意,这是我的个人意见 ,因为我现在无法certificate它除了代码段testing协议有和没有别名。

必须使用协议? 我对types理论的把握不是很好,但是根据苹果的讨论和上面的讨论,问题似乎又回到了“更高级的types”这个话题上。

也就是说,如果你可以使用抽象基类来进行近似处理(注意它并不是真正的抽象,并且不能用于结构),用下面的forms:

 class AnyTrain<CarriageType> { func addCarriage(carriage: CarriageType) {} func shortTrain() -> AnyTrain<CarriageType> { return AnyTrain<CarriageType>() } } class SimpleTrain<T> : AnyTrain<T>, Printable { private var carriages: [T] = [T]() override func addCarriage(carriage: T) { carriages.append(carriage) } override func shortTrain() -> AnyTrain<T> { let short = SimpleTrain<T>() short.addCarriage(carriages[0]) return short //COMPILE ERROR: SimpleTrain<T> is not convertible to 'ShortType' } var description:String { return "Train: \(carriages)" } } let train = SimpleTrain<Int>() train.addCarriage(1) train.addCarriage(2) train.addCarriage(3) let shortTrain = train.shortTrain() println(shortTrain) // obviously you can refer to it as the base let anotherTrain:AnyTrain<Int> = SimpleTrain<Int>() anotherTrain.addCarriage(3) anotherTrain.addCarriage(2) anotherTrain.addCarriage(1) let anotherShortTrain = anotherTrain.shortTrain() println(anotherShortTrain) 

这输出:

火车:[1]

火车:[3]

我已经尝试过这种技术,我有抽象层次结构的情况下,其中一个types是共同的,其他的不同,但不影响function签名。 通过使用“抽象类”,我可以创build一个“任何types与这个通用types的共同(而其他人可以不同)”的数组“