这是对这个问题的跟进:Protocol func returning Self。该议定书如下:
protocol Copyable {
init(copy: Self)
func copy() -> Self
}下面的功能很好,但是对于每个实现来说,copy()函数是完全相同的,即
func copy() -> Self {
return self.dynamicType(copy: self)
}根据这个http://nshipster.com/swift-default-protocol-implementations/,我尝试了一个全局函数
func copy<T : Copyable>(makeCopy: T) -> T {
return makeCopy.dynamicType(copy: makeCopy)
}但是,当它在实现以下协议的类中调用时
protocol Mutatable : Copyable {
func mutated() -> Self
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
func mutated() -> Self {
let mutated = copy(self)
mutated.a++
return mutated // error: 'C' is not convertible to 'Self'
}
}如前所述,我得到了错误。当我输入mutated时,自动完成将mutated显示为(C),我不知道这意味着什么。我也尝试过将required添加到func mutated()中,但显然required只允许用于inits。有什么办法让这件事起作用吗?
发布于 2014-09-06 14:47:04
这个问题的形式和副本相同,解决方案也是一样的。使突变成为一个初始化器,而不是一个方法。
protocol Copyable {
init(copy: Self)
}
protocol Mutatable : Copyable {
init(byMutating: Self)
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
required convenience init(byMutating: C) {
self.init(copy: byMutating)
self.a++
}
}
// These are purely for convenience
func copy<T : Copyable>(x: T) -> T {
return x.dynamicType(copy: x)
}
func mutated<T: Mutatable>(x: T) -> T {
return x.dynamicType(byMutating: x)
}但是,为了重申Mattt在链接文章中的观点,您可以相当方便地使用C(copy: x)语法,并且可以非常方便地使用copy(x)语法,并且始终存在x.dynamicType(copy: x)。但是,如果没有一些烦人的工作,就不能使用x.copy()语法。您要么必须在每个类中复制func copy() -> Self { return copy(self) },要么必须创建一些具体的类来实现该方法并最终继承C。这是Swift目前的一个基本限制。我同意Mattt对可能的解决方案的诊断,并怀疑将来可能会添加某种特性系统,可能类似Scala那样。
值得关注的是Mattt的评论,“所有这些都突出了Swift中的方法和功能之间的紧张关系。”这是另一种说法,即面向对象的范式和功能范式之间存在着紧张关系,而在它们之间的移动会造成一些脱节。语言试图用不同的特性来掩盖这个问题,但在具有消息和属性的对象、带有数据和组合器的vs函数之间存在着重要的差异,而“充分利用这两个世界”有时会产生一些粗糙的边缘。
当将Swift与其他语言进行比较时,很容易忘记,v0.9和v2.11之间有很大的差别。在我们最喜欢的语言中,我们认为理所当然的许多事情也不存在于它们的v1中。
对于您的评论,您可能会认为mutated是Self类型。但是它是C类型的,正如您的自动完成指示的那样。和以前一样,C与Self不同,除非您可以保证没有子类(C是final或结构)。除非使用dynamicType,否则Swift类型是在编译时解析的,而不是运行时。
更具体一点的是,Swift看了这一行:
let mutated = copy(self)它注意到copy在其参数的类型上是通用的,它必须在编译时构造一个copy版本来调用。没有Self类型。它只是一个占位符,必须在编译时解析。这个词法作用域中的self类型是C。因此,它构造了copy<C>。但是,如果您子类C,这可能是错误的函数(在本例中,将是)。这与:https://stackoverflow.com/a/25549841/97337密切相关。
类型自动完成说(C)而不是C是Swift函数和元组工作方式的一个小副作用,并且经常出现,但我还没有遇到真正重要的情况。像func f(x: Int, y:Int)这样的Swift函数实际上没有两个参数。它有一个(Int, Int)类型的二元组参数.这个事实对于当前语法的工作方式是很重要的(请参阅Swift编程语言以获得更多关于在Swift中运行的信息)。因此,当您专门化copy时,您使用的是(C)类型的一元组。(或者可能的话,编译器只是尝试将其作为各种尝试中的一种,而这正是它所报告的。)在Swift中,任何值都可以用相同类型的一元组来交换。所以copy的返回实际上是C的一个元组,写的(C)。我怀疑Swift编译器会随着时间的推移而改进其消息以删除无关的括号,但这就是它们有时出现的原因。
https://stackoverflow.com/questions/25695091
复制相似问题