请参见下面的自包含示例。编译器在最后一行(由标记为COMPILE ERROR
)报告错误,在该行中,我将实例分配给SimpleTrain
它(根据我的最佳判断)符合的协议类型。如何编译?我究竟做错了什么?还是这个编译器问题?
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'
}
}
编辑: 即使我明确地向下转换了shortTrain
上面的返回类型(以便上面的代码片段的最后一行读取return short asShortType
),如安东尼奥在调用函数时仍然存在编译错误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'
这是因为您没有给编译器足够的信息来确定的类型a
。想一想它所看到的:
func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType {
let a = s.shortTrain()
编译器需要a
在编译时确定类型,并且不能处理抽象类型。它需要一个完全指定的类型ShortType
(确定所有内容;指定所有泛型,解析所有类型别名)。它环顾四周,并看到对的一些约束ShortType
,但看不到实际提供类型的任何东西。它所具有的只是a
,没有给出任何提示。
不幸的是,这使您不得不明确地告诉它要发生的事情。
let a: SimpleTrain<String> = s.shortTrain()
这可能与您想要的相反,但现在您可以在Swift中完成所有操作。Swift团队已经表明(很多次)他们非常了解与关联类型有关的这些问题(以及类型系统中的其他一些相关弱点)。他们特别了解可以处理这些事情的Scala类型系统,并且与当前的Swift类型系统有很多共同点(尽管以我的经验,在Scala中使用复杂的与路径相关的关联类型也可以导致头发撕裂)。
就是说,从您的示例中并不能完全清楚您计划如何使用此功能。某些火车会返回与shortTrain()不同的类型吗?
我发现这些问题通常在一般情况下会爆发,但在您面前的应用程序的特定情况下往往可以解决。很难在Swift中用代码来解决任何问题来构建真正的任意类型,但是当您专注于真正需要的类型时,通常会奏效。例如,如果shortTrain()
返回Self
,这显然会变得更简单。如果呼叫者知道所需的结果类型,则init(shorten:)
可能可以处理它。类似的协议方法shortCarriages() -> [CarriageType]
可以提供良好的桥梁。保持设计的灵活性,几乎可以肯定其中之一是可行的。
问题内容: A类提供一个字符串值。类B在其内部具有两个A类型的成员,并提供一个计算属性“ v”来选择其中之一。 这段代码很简单,可以正常工作。由于A和B都具有成员“值”,因此我将其设为这样的协议: 如果我更改以下代码 至 它再次起作用! 这是Swift的错误,还是协议属性的特殊之处? 问题答案: 您必须将协议定义为协议: 然后 编译并按预期方式工作(即,将新值分配给if 所引用的对象,否则分配给否
问题内容: 更新到xcode 8 beta 6后,出现错误 无法将’()-> Void’类型的值分配给’(()-> Void)!’ 在以下func块的第三行: 关于修复的任何建议? 问题答案: 看来您的问题与此有关: SE-0103 尝试将您的方法标头追踪到: 与往常一样,来自新Beta的诊断消息是如此混乱和不足,但是将您的媒体资源设置为非可选将为您提供更多有用的信息。
问题内容: 这是我写该行时的错误: /ChatApp/ViewController.swift:27:42:无法将“ ViewController”类型的值分配给“ UITextFieldDelegate”类型的值? 这是我的Swift代码(ViewerController.swift): 问题答案: 该生产线将导致错误,因为你尝试分配作为的。 但是,你 是不是 一个。为了使您的课程成为此类委托,
我尝试了几种解决方案,但都不管用
你好,我在小部件上的以下代码中出错 参数类型'List 这是我的代码 我的代码与上面的图表插件不兼容吗?如何解决这个问题?
问题内容: 我有一个协议,该协议继承自另一个协议,并且满足扩展要求。 还有另一种协议,其要求()应该为。 现在,如果我尝试使用as ,那么它将无法编译。它说, 推断的类型“地址”(通过匹配要求“ valueForDetail”)无效:不符合“ Validator”。 这种用法非法吗?我们不能像所有的那样用它代替。 下面是我正在尝试的代码。 更新: 提交了一个错误。 问题答案: David已经提到的