Swift:约束泛型参数以在更受约束的泛型函数中使用

时间:2018-08-21 17:36:33

标签: swift function generics

我正在实现一个类,该类需要符合如下所示的协议:

protocol P {
    func magic<T>(_ thing: Thing, as type: T.Type) -> T
}

此协议由第三方代码提供,这意味着我无法以任何方式对其进行更改以解决此问题。

现在,我有一个通用函数

func magicForObject<T: AnyObject>(_ thing: Thing, as type: T.Type) -> T

,我想从magic的实现中调用它,只针对实际上是对象的输入thing。 也就是说,我想做这样的事情:

func magic<T>(_ thing: Thing, as type: T.Type) -> T {
    if T.self is AnyClass {
        return magicForObject(thing, as: type)
    }
    else {
        // do something else
    }
}

但是我找不到任何方法可以完成这项工作。上面的代码显然不会编译,类似

的东西也不会编译
if let T_ = T.self as? AnyClass { ... }

因为T_只是一个普通变量,而不是通用参数(可能是编译时)。

我也尝试这样做:

func magic<T: AnyObject>(_ thing: Thing, as type: T.Type) -> T { ... }
func magic<T>(_ thing: Thing, as type: T.Type) -> T { ... }

并分别实现两者。如果直接在对象上调用受约束的AnyObject,则正确调用该函数;而当对象强制转换为协议类型P时,则不是;在这种情况下,第二个是一直使用。

这种情况似乎无可救药地受到限制,但是有没有我没有想到的解决方法?

更新

看起来这在Swift中目前是不可能的。我在Swift论坛上做了一个post pitching the idea;如果您也需要此功能,请随时鸣叫。

1 个答案:

答案 0 :(得分:1)

您的示例很难处理,因此我不得不做很多假设,但是我想这应该满足您的要求。

根据您所说的,您具有给定的协议P:

protocol P {
    func magic<T>(_ thing: Thing, as type: T.Type) -> T
}

让P默认实现您需要执行的操作:

extension P {
    // Implementation for magic where T is a class
    func magic<T>(_ thing: Thing, as type: T.Type) -> T where T: AnyObject {
        print("AnyObject Called")
        return Test2() as! T
    }

    // Implementation for magic where T is a struct
    func magic<T>(_ thing: Thing, as type: T.Type) -> T {
        print("Struct Called")
        return Test() as! T
    }
}

您有一个符合P

的课程
class Test2: P {

}

让我们假设您拥有这个Thing对象和一个我们想要传递的结构,以查看我们是否具有正确的结果:

class Thing {

}

struct Test {

}

现在让我们测试是否在magic上调用Test2,是否将根据传递给type的内容magic调用正确的函数

let test = Test()
let test2 = Test2()

// T is Test2 so its a class
test2.magic(Thing(), as: Test2.self)
// T is Test so its a struct
test2.magic(Thing(), as: Test.self)

打印输出调用

AnyObject Called
Struct Called

似乎您可以为structs做某事,为classes做另一件事