Swift 将功能附加到子类中重写的泛型方法
考虑一下这个代码片段Swift 将功能附加到子类中重写的泛型方法,swift,generics,Swift,Generics,考虑一下这个代码片段 类Op{ func exec()->T{ fatalError(“未实施”) } } 类SubOp:Op{ 重写func exec()->U{ //1.将产生错误:“无法转换返回表达式” //类型为“()”以返回类型“U” 多斯塔夫() //2.无法调用'return super.exec()`生成有效的返回 //类型,因为基类未实现exec()。 } func doStuff(){ 打印(“内容”) } } 我有一个泛型基类Op,它的exec()方法有一个空实现,需要在
类Op{
func exec()->T{
fatalError(“未实施”)
}
}
类SubOp:Op{
重写func exec()->U{
//1.将产生错误:“无法转换返回表达式”
//类型为“()”以返回类型“U”
多斯塔夫()
//2.无法调用'return super.exec()`生成有效的返回
//类型,因为基类未实现exec()。
}
func doStuff(){
打印(“内容”)
}
}
我有一个泛型基类Op
,它的exec()
方法有一个空实现,需要在子类中重写。为了绕过这个讨厌的通用返回值,插入了一个永远不会返回的fatalError
。但是,如果子类必须向该方法添加功能,则它不能,因为它必须调用super
来创建有效的返回类型
现在我可以要求子类通过API契约调用另一个方法,例如在其泛型exec()
方法中调用doStuff
,但这似乎不是一个好主意
有没有更好的模式来解决这个问题
PS:我知道这段代码不正确,它只是在这里演示它应该实现的功能。我不太确定您的问题是什么: 如果你写信
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()
你必须归还一些东西。问问芭芭拉·利斯科夫
更新二
您还可以将闭包交给exec
,然后子类实现可以决定是否调用该闭包。
注意:由于SubOb.exec
中的let theU=U()
语句,您只需要Initable
协议一致性。如果不创建任何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)
公共协议可初始化{
init()
}
扩展名Int:Initable{}
类Op{
typealias回调=(T)->()
func exec(cb:回调){
//什么都不做。或者崩溃:
//fatalError(“未实施”)
}
}
类SubOp:Op其中U:Initable{
重写func exec(cb:回调){
多斯塔夫()
设U=U()
cb(theU)
}
func doStuff(){
打印(“内容”)
}
}
设so=SubOp()
让intCallback:(Int)->()={
(intValue:Int)in
打印(“使用值\(intValue)调用”)
}
so.exec(cb:intCallback)
像安德烈亚斯一样,我也不知道你想做什么。您为什么要将T
重命名为U
,您打算如何使用它?为什么要使用子类化呢
如果没有更多信息,我们无法说明您为什么不这样做:
最终类子类:Op{
重写func exec(){
打印(“内容”)
}
}
这不起作用,因为您现在将doStuff
设置为泛型,所以这只不过是将代码直接移动到exec()
,因此没有意义。这只是为了允许使用单个doStuff
语句。查看我的更新。因为swift不支持抽象类,所以在我看来Op应该是一个协议,而不是协议。是的,我考虑过了。问题是协议是如何在Swift中实现的。使用associatedtypes
带来了全新的痛苦。另一种选择是将T设为可选,因为在我看来,您并不总是希望exec()函数创建并返回T类型的值。这也是真的。不过,我会将问题推迟到来电者,来电者必须再次打开。似乎没有令人满意的答案。另一个例子是,如果一个子类决定返回Void
,它将生成一个Void?
可选。@ErikAigner我注意到您仍然没有因为在这里的评论中的粗鲁行为而被暂停。你能要求你也有一个为期一周的禁令吗?我觉得你的行为比我的更糟,这就是我受到的惩罚。不过,如果我们都收到同样的礼物,我会很高兴的。非常感谢。
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)