Swift 通用函数调用另一个通用函数

3

我正在使用XCode 7.3.1上的Swift 2.2,尝试从另一个泛型函数中调用泛型函数。

代码

class Thing1 {
     let variable: SomeProtocol
     init<A: SomeProtocol>(variable: A) {
          self.variable = variable
          self.add1(self.variable)
     }

     func add1<A: SomeProtocol>(stuff: A) {
          let thing: Thing2 = Thing2()
          thing.add2(stuff)
     }

}

class Thing2 {
    func add2<A: SomeProtocol>(stuff: A) {

    }
}

protocol SomeProtocol { }


add1("a") // Cannot invoke 'add1' with an argument list of type '(String)'
add1(4) // Cannot invoke 'add1' with an argument list of type '(Int)'

我遇到了错误。
'Cannot invoke add with an argument of list type '(Whatever type I used to call the function)''

我稍微整理了一下代码。在 playground 中编译没有问题,但是当你尝试调用 'add1' 时它不允许你这样做。 - Cody Weaver
@CodyWeaver,你能否提供一个最小化的示例,尽可能接近编译状态?这样,我们就可以进行一致的测试,而不必自己实现SomeProtocolThing等内容。 - Alexander
添加了代码以使其更清晰明了。 - Cody Weaver
1
@CodyWeaver,你是否已经确认了要访问 add1 的类型属于 SomeProtocol?例如 extension String : SomeProtocol { }extension Int : SomeProtocol { } - dfrib
是的,我添加了这些扩展。我还添加了更多的代码以展示更多的用例。 - Cody Weaver
2个回答

2
问题在于Swift中的抽象类型不一定符合自身,因此您不能将一个SomeProtocol类型的东西用作符合SomeProtocol的具体类型(这是您的add1通用函数期望的参数)。因此,在您的情况下,最简单的解决方案就是使用通用的variable参数而不是variable属性,因为它是通用的,所以它被类型化为符合SomeProtocol的具体类型,因此可以传递到您的add1函数中。
init<A: SomeProtocol>(variable: A) {
    self.variable = variable
    add1(variable)
}

然而,为了防止这些问题在以后出现,您可能需要考虑使您的类成为通用类,假设在给定的Thing1实例的整个生命周期中,您的variable属性应该是一个常量类型。
class Thing1<A:SomeProtocol> {

    let variable: A

    init(variable: A) {
        self.variable = variable
        add1(variable)
    }

    func add1(stuff: A) {
        let thing = Thing2()
        thing.add2(stuff)
    }
}

或者,你可以重构你的代码来使用抽象类型SomeProtocol,这将允许你处理符合SomeProtocol的任何类型(例如,在数组中混合不同的Thing1实例和不同的variable类型):
class Thing1 {

    let variable: SomeProtocol

    init(variable: SomeProtocol) {
        self.variable = variable
        add1(variable)
    }

    func add1(stuff: SomeProtocol) {
        let thing = Thing2()
        thing.add2(stuff)
    }
}

class Thing2 {
    func add2(stuff: SomeProtocol) {

    }
}

尽管您应该始终意识到使用抽象类型所带来的额外成本,但是请参阅这个很棒的WWDC演讲以获取更多信息

0

将扩展添加到StringInt并构造Thing1对象使其正常工作:

extension String: SomeProtocol{}
extension Int: SomeProtocol{}

Thing1(variable: "a").add1("a")
Thing1(variable: 2).add1(4)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接