无法将类实例分配给其协议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。 它需要一个完全指定的ShortType
types(所有的指定,所有的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,这意味着您不能声明具有ProtocolWithAlias
types的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的共同(而其他人可以不同)”的数组“
- iOS:具有-webkit-backface-visibility的多个div:缩放时隐藏崩溃浏览器
- 什么是声明`typedef SomeClass <SomeProtocol> MyType`的Swift等价物?