考虑这个代码片段
class Op<T> {
func exec() -> T {
fatalError("not implemented")
}
}
class SubOp<U>: Op<U> {
override func exec() -> U {
// 1. Would produce an error: "Cannot convert return expression
// of type '()' to return type 'U'"
doStuff()
// 2. Cant call `return super.exec()` to produce a valid return
// type because base class doesn't implement exec().
}
func doStuff() {
print("stuff")
}
}
我有一个通用基类 Op
,它的 exec()
方法有一个空实现,需要在子类中重写。为了绕过那个讨厌的通用返回值,插入了一个永远不会返回的 fatalError
。但是,如果子类必须为此方法添加功能,则不能,因为它必须调用 super
来创建有效的返回类型。
现在我可以要求子类调用另一个方法,例如doStuff
通过 API 合同在其通用 exec()
方法中使用,但这似乎不是一个好主意。
有没有更好的模式来解决这个问题?
PS:我知道这段代码不正确,只是为了演示它应该实现的功能。
答案 0 :(得分:0)
我不太确定你的问题是什么: 如果你写
override func exec() -> U {
doStuff()
}
这肯定是不正确的,因为 doStuff
不返回任何东西(只有 void
,它是 ()
的别名)
如果您调用 super.exec()
,您的应用程序将崩溃。我想这不是你想要的。
您是否要求类似的东西
public protocol Initable {
init()
}
extension Int:Initable {}
class Op<T> {
func exec() -> T {
fatalError("not implemented")
}
}
class SubOp<U>: Op<U> where U:Initable {
override func exec() -> U {
doStuff()
}
func doStuff() -> U {
print("stuff")
return U()
}
}
let so = SubOp<Int>()
var i = so.exec()
如果你不想doStuff
返回一些东西,你需要写:
override func exec() -> U {
doStuff()
return U()
}
func doStuff() {
print("stuff")
}
您必须退货。问问芭芭拉·利斯科夫。
您也可以将闭包交给 exec
,然后子类实现可以决定是否调用该闭包。
注意:您只需要符合 Initable
协议,因为 let theU = U()
中有 SubOb.exec
语句。如果您不创建任何 U
对象而是从其他地方获取它们,则可以跳过此步骤。
public protocol Initable {
init()
}
extension Int:Initable {}
class Op<T> {
typealias Callback = (T)->()
func exec(cb:Callback) {
// Just do nothing. Or crash:
// fatalError("not implemented")
}
}
class SubOp<U>: Op<U> where U:Initable {
override func exec(cb:Callback) {
doStuff()
let theU = U()
cb(theU)
}
func doStuff() {
print("stuff")
}
}
let so = SubOp<Int>()
let intCallback:(Int)->() = {
(intValue:Int) in
print ("called with value \(intValue)")
}
so.exec(cb:intCallback)
答案 1 :(得分:-2)
和 Andreas 一样,我也不知道你想做什么。您为什么将 T
重命名为 U
,您打算如何使用它?你为什么要使用子类化?
如果没有更多信息,我们无法判断您为什么不这样做:
final class SubOp: Op<Void> {
override func exec() {
print("stuff")
}
}