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)