无法将类实例分配给其协议类型? [英] Cannot assign class instance to its protocol type?
问题描述
请参阅下面的自我举例。编译器报告最后一行(标记为 COMPILE ERROR
)的错误,其中我将 SimpleTrain
的实例分配给协议类型(在我最好的判断)符合。我如何使它编译?我做错了什么?
协议Train {
typealias CarriageType
func addCarriage () - < ShortType:Train:CarriageType)
func shortTrain< ShortType:Train where ShortType.CarriageType == CarriageType>() ShortType
}
class SimpleTrain< T> :train {
typealias CarriageType = T
private var carriageages:[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>不能转换为'ShortType'
}
}
EDIT:即使我明确地向下转换了 shortTrain
的上面的返回类型作为 Antonio建议读取以ShortType
返回简短,仍然有调用函数时出现编译错误:
let s = SimpleTrain< String> ;()
s.addCarriage(Carriage 1)
s.addCarriage(Carriage 2)
让a = s.shortTrain()//错误:将表达式类型'()'转换为类型'Train'
let b = s.shortTrain< SimpleTrain< String>>()//错误:不能显式地专门化通用函数
解决方案首先,您要阅读 canonical thread 在这里从devforums。
现在转到已编辑的问题:
let a = s.shortTrain()//错误:无法将表达式类型'()'转换为类型'Train'
这是因为你没有给编译器足够的信息来确定
a
的类型。想想看到的内容:func shortTrain< ShortType:Train where ShortType.CarriageType == CarriageType>() - > ShortType {
let a = s.shortTrain()
编译器需要找出类型
a
在编译时,它不能处理抽象类型。它需要一个完全指定的类型ShortType
(一切钉住;所有的泛型指定,所有的类型别名解析)。它看起来周围,它看到一些约束在ShortType
,但它没有看到任何实际上给一个类型。它所有的是a
,它不给它任何提示。
不幸的是,明确告诉它你想要发生什么。
让a:SimpleTrain< String> = s.shortTrain()
这可能与你要做的相反,你现在可以在Swift中做。 Swift团队(多次)表示他们很清楚这些问题与相关类型(以及类型系统中的其他一些相关弱点)。他们特别意识到可以处理这些事情的Scala类型系统,并且与当前的Swift类型系统有很多共同点(虽然在我的经验中,获取复杂的依赖于路径的相关类型在Scala中工作也可能导致头发撕裂)。
也就是说,从你的例子中你并不清楚你打算用这个功能。会有一些火车返回一个不同的类型作为他们的shortTrain()?
我发现这些问题往往在一般情况下爆炸,但往往是相当可解的特定在你面前的应用程序的情况。很难在Swift中用可以解决每个问题的代码构建真正的任意类型,但是当你专注于真正需要的类型时,它通常会奏效。例如,如果
shortTrain()
返回Self
,这显然变得更简单。如果调用者知道所需的结果类型,那么init(shorten:)
可能会处理它。一种协议方法,例如shortCarriages() - > [CarriageType]
可以提供一个好的桥梁。保持您的设计灵活性,其中一个几乎肯定会解决。Please see self containing example below. Compiler reports an error on the last line (marked by
COMPILE ERROR
) where I am assigning an instance ofSimpleTrain
to a protocol type that it (in my best judgement) conforms to. How can I make it compile? What am I doing wrong? Or is this compiler issue?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' } }
EDIT: Even when I explicitly downcast the
shortTrain
's return type above (so that last line of code snippet above readsreturn short as ShortType
) as suggested by Antonio there is still compilation error when calling functionshortTrain
: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
解决方案First, you want to read the canonical thread on this from devforums. You particularly want to skip around to read jckarter's comments.
Now to the edited question:
let a = s.shortTrain() //ERROR: Cannot convert the expression's type '()' to type 'Train'
This is because you haven't given the compiler enough information to determine the type of
a
. Think through what it sees:func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType { let a = s.shortTrain()
The compiler needs to figure out the type of
a
at compile time, and it can't handle abstract types. It needs a fully specified type forShortType
(everything nailed down; all the generics specified, all the type aliases resolved). It looks around, and it sees some constraints onShortType
, but it doesn't see anything that actually gives a type. All it has isa
, which isn't giving it any hints.So unfortunately, that leaves you having to tell it explicitly what you want to happen.
let a: SimpleTrain<String> = s.shortTrain()
That's probably the opposite of what you were going for, but it's about all you can do in Swift right now. The Swift team has indicated (many times) that they are well aware of these issues with associated types (and several other related weaknesses in the type system). They're specifically aware of the Scala type system which can handle these things and has a lot in common with the current Swift type system (though in my experience, getting complex path-dependent associated types to work in Scala can also lead to hair tearing).
That said, it's not exactly obvious from your example what you planned to do with this functionality. Would some Trains return a different type as their shortTrain()?
I find that these problems often blow up in the general case, but tend to be quite solvable in the specific cases for the app in front of you. It's hard to build really arbitrary types in Swift in code that could solve every problem, but it often works out when you focus on the types you'll really need. For example, if
shortTrain()
returnedSelf
, this obviously gets simpler. If the caller knows the desired resulting type, then aninit(shorten:)
can probably handle it. A protocol method likeshortCarriages() -> [CarriageType]
may provide a good bridge. Stay flexible on your design, and one of them will almost certainly work out.这篇关于无法将类实例分配给其协议类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!