协议和通用功能中的关联类型用法

时间:2018-11-22 17:28:39

标签: swift generics protocols swift-protocols

假设我有一个protocol Foo和一个associatedtype Bar。有什么办法可以使用相同的 associatedtype 作为该相同协议内泛型函数的约束?

说明:

protocol Foo {
    associatedtype Bar
    func example<T: Bar>() -> T
}

这将引发Inheritance from non-protocol, non-class type 'Self.Bar'。这很有意义,因为在编译时,我们不知道Bar将是哪种类型

尽管如此,由于某种原因,即使我定义了Bar类型,我仍然会遇到相同的错误。像这样:

protocol Foo {
    associatedtype Bar: NSObject //OR: Protocol
    func example<T: Bar>() -> T //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar'
}

thisthis这两个问题都解决了同一问题,但根据我的诚实意见,它们都不是真正的答案。

此外,也许我是从一种错误的语言角度来解决这个问题的,但是为了使我的用例形象化:我需要在类定义Bar的类型时,每个T用于example()函数应为Bar类型,但要知道它将返回哪种类型。 为了说明我的艺术水平:

protocol Foo {
    associatedtype Bar: NSObject //OR: Protocol
    //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar'
    func example<T: Bar>() -> T //OR: func example<T>() -> T where T: Bar
}

class ExampleBarType: NSObject { }

class ExampleObject: ExampleBarType { }

class FooImplementation: Foo {
    typealias Bar = ExampleBarType

    func example<T: Bar>() -> T { //OR: func example<T>() -> T where T: Bar {

    }
}

我似乎无法理解为什么编译器不能假设我的关联类型将是我定义的类型。预先感谢。

3 个答案:

答案 0 :(得分:0)

我知道这是一个高级话题。希望这种方式可以给你一些照明。

protocol Foo {
associatedtype Bar: NSObject //OR: Protocol
func example() -> Bar  //OR:
}

class ExampleBarType: NSObject { }

class ExampleObject: ExampleBarType { }

class FooImplementation: Foo {
typealias Bar = ExampleBarType
func example<T: Bar>() -> T {
    return Bar.init() as! T
}
}

答案 1 :(得分:0)

我不确定我是否完全了解您的用例,但这还不足以完成您需要做的事情吗?

protocol Foo {
    associatedtype Bar
    func example() -> Bar
}

protocol BarProtocol { }

class BarOne: BarProtocol { }

class BarTwo: BarProtocol { }

class FooImplementationOne: Foo {
    func example() -> BarProtocol {
        return BarOne()
    }
}

class FooImplementationTwo: Foo {
    func example() -> BarProtocol {
        return BarTwo()
    }
}

答案 2 :(得分:0)

您在这里设计的内容无法实现。这不是一个Swift问题。我的意思是说这实际上是不可能实现的,因为类型不能实现您所需要的承诺。考虑这一部分:

class ExampleBarType {} // Not an NSObject subclass.

class FooImplementation: Foo {
    typealias Bar = ExampleBarType

    func example<T: Bar>() -> T {
        // What would you write here?
    }
}

您打算如何编写该函数体?考虑以下呼叫者:

class MyBar: Bar {        
    init(x: Int) {}
}

let ex: MyBar = foo.example()

您将如何实施example?您如何构造MyBar?您不知道init方法的参数(它需要一个您没有的Int)。但是您的函数签名声称此函数将返回调用者请求的Bar的任何特定子类。

通常,应避免在同一类型系统中混合使用协议,泛型和子类。它们向不同的方向拉动,很难保持系统的一致性。在很多情况下,您将无法兑现诺言。

您应该回到您的具体问题和需求。如果您这样做是“因为我想尽可能地通用”,建议您停止。 Swift类型的系统非常强大,但也有一些非常棘手的限制,并且“尽可能通用,因为”几乎总是会遇到这些限制。但是,如果您在实际程序中有具体的用例,那么您经常(尽管并非总是)可以避免这些麻烦。