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' } }
我收到了错误,如上所述.当我输入变异的自动完成显示变异为(C),我不知道这意味着什么.我也尝试添加func mutated()所需但显然只需要inits.有什么办法让这个工作?
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() – >每个类中都有自我{return copy(self)},或者您必须创建一个实现此方法的具体类,并且C最终继承自.这是目前Swift的一个基本限制.我同意Mattt对可能解决方案的诊断,并怀疑将来可能会添加某种特征系统,可能与Scala一样.
值得关注的是Mattt的评论,“所有这些都凸显了Swift中方法与功能之间的紧张关系.”这是另一种表达面向对象范式与功能范式之间存在紧张关系的方式,在它们之间移动可能会产生一些断开连接.语言试图通过各种功能来解决这个问题,但是具有消息和属性的对象与具有数据和组合器的函数之间存在重要差异,并且“充分利用两个世界”有时会产生一些粗糙的边缘.
在将Swift与其他语言进行比较时,很容易忘记v0.9和v2.11之间存在很大差异.我们在我们最喜欢的语言中认为理所当然的许多事情也不存在于他们的v1中.
对于你的评论,你可能会认为变异是Self类型.但它是C类型,因为您的自动完成功能表明了这一点.和以前一样,除非你能保证没有子类(C是final或struct),否则C与Self不同. Swift类型在编译时解析,而不是运行时,除非您使用dynamicType.
更具体一点,Swift看到了这一行:
let mutated = copy(self)
它指出副本在其参数类型上是通用的,它必须在编译时构造一个版本的副本来调用.没有自我类型.它只是一个占位符,必须在编译时解决.这个词法范围中的self类型是C.因此它构造了copy< C>.但是如果你将C子类化,那么这可能是错误的功能(在这种情况下,将是).这与:https://stackoverflow.com/a/25549841/97337密切相关.
类型自动完成说(C)而不是C这一事实是Swift函数和元组如何工作的一个小副作用,并且经常出现,但我还没有遇到一个真正重要的案例.像func f(x:Int,y:Int)这样的Swift函数实际上没有两个参数.它有一个2元组参数类型(Int,Int).这个事实对于currying语法的工作原理很重要(有关Swift中的currying的更多信息,请参阅Swift编程语言).因此,当您专门复制时,您将其专门化为一个类型为(C)的元组. (或者可能,编译器只是试图将其作为各种尝试中的一种,而这只是它报告的那种.)在Swift中,任何值都可以简单地交换为相同类型的1元组.所以副本的返回实际上是C的1元组,写成(C).我怀疑Swift编译器会随着时间的推移改进其消息以删除无关的括号,但这就是它们有时出现的原因.