简体   繁体   English

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

[英]Swift: constrain a generic parameter for use in a more constrained generic function

I'm implementing a class which needs to conform to a protocol that looks like this:我正在实现一个需要符合如下协议的类:

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

This protocol is provided by third-party code, which means I can't change it in any way in order to solve this problem.此协议由第三方代码提供,这意味着我无法以任何方式更改它以解决此问题。

Now, I have a generic function现在,我有一个通用函数

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

and I want to call it from within my implementation of magic , just for input thing s which are in fact objects.我想从我的magic实现中调用它,只是为了输入的thing ,它们实际上是对象。 That is, I want to do something like this:也就是说,我想做这样的事情:

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

but I can't find any way to make this work.但我找不到任何方法来完成这项工作。 The code above obviously doesn't compile, and neither does stuff like上面的代码显然不能编译,类似的东西也不能编译

if let T_ = T.self as? AnyClass { ... }

because T_ is just a normal variable, not a generic parameter (which is presumably compile-time).因为T_只是一个普通变量,而不是一个通用参数(大概是编译时)。

I also tried doing this:我也试过这样做:

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

and implementing the two separately.并分别实施两者。 The constrained AnyObject one is correctly called if calling this function directly on the object, but not when the object is cast to protocol type P , in which case the second one is always used.如果直接在对象上调用此函数,则会正确调用受约束的AnyObject ,但在将对象AnyObject为协议类型P时则不会,在这种情况下,始终使用第二个。

This situation seems hopelessly constrained, but are there any workarounds I haven't thought of?这种情况似乎无可救药地受到限制,但有没有我没有想到的解决方法?

Update更新

It looks like this isn't currently possible in Swift.看起来这在 Swift 中目前是不可能的。 I've made a post pitching the idea in the Swift forums;我在 Swift 论坛上发表了一篇文章来宣传这个想法 please feel free to chime in if this is something you also need.如果这也是您需要的东西,请随时加入。

Your example is kind of hard to work with, so I had to do a lot of assumptions, but I guess this should do it for what you are requiring.你的例子有点难以使用,所以我不得不做很多假设,但我想这应该满足你的要求。

From what you said you have a given protocol P:根据您所说的,您有一个给定的协议 P:

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

Lets give P a default implementation of what you need it to do:让我们给 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
    }
}

You have a class that will conform to P你有一个符合 P 的类

class Test2: P {

}

Lets assume you have this Thing object and a struct we want to pass to see if we have the right results:让我们假设你有这个 Thing 对象和一个我们想要传递的结构,看看我们是否有正确的结果:

class Thing {

}

struct Test {

}

Now lets test if we call magic on Test2 if it will call the right function accordingly to what type is passed to magic现在让我们测试一下我们是否在Test2上调用magic是否会根据传递给magic type调用正确的函数

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)

The Print Output calls打印输出调用

AnyObject Called
Struct Called

which seems like you could do something for structs and another thing for classes看起来你可以为structs做一些事情,而为classes做另一件事

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM