【问题标题】:Specialize generic function requirement on protocol inheritance专门针对协议继承的通用功能需求
【发布时间】:2018-01-22 12:20:56
【问题描述】:

我的代码中有一些协议层次结构,其中有定义我使用的对象的协议和定义与这些对象一起使用的函数的协议。

对象协议被其他对象协议继承,这些协议向原始协议添加了更多功能,使用它们的功能也是如此。问题是我找不到专门化函数以仅采用继承参数的方法。

这里有一些代码来说明我想要做什么:

protocol A {
    var foo: String { get set }
}
protocol B: A {
    var bar: String { get set }
}

struct Test: B {
    var foo: String = "foo"
    var bar: String = "bar"
}

protocol UseAProtocol {
    static func use<T: A>(_ obj: T)
}

protocol UseBProtocol: UseAProtocol {
}

extension UseBProtocol {
    //If I change the requirement to <T: B> this won't conform to `UseAProtocol`.
    static func use<T: A>(_ obj: T) {
        print(obj.foo)
        // print(obj.bar) - Since obj does not conform to `B` I can't access ".bar" here without a forced casting.
    }
}

struct Manager: UseBProtocol {
}

Manager.use(Test())

我想做的是让UseBProtocol 上的use 函数只接受符合B 的对象。 B 继承自 A,但是当我从 &lt;T:A&gt; 更改为 &lt;T:B&gt; 时出现错误,提示 Manager 不符合 UseAProtocol,我必须将其改回 &lt;T:A&gt;

我知道我可以在继承协议上使用 associatedtypewhere 子句来做到这一点——这就是我今天使用的——但我想将通用要求移到方法中,这样我就可以将所有这些组合在一起相同的结构(我有很多这种层次结构,通过使用associatedtype,我必须按层次结构使用一个结构)。当条件一致性来到 Swift 时,associatedtype 就可以实现,但直到他们......

我也可以使用as! 来强制在UseBProtocol 实现上从A 强制转换为B,但这是一个非常糟糕的解决方案,并且只会在运行时抛出错误。

有什么方法可以实现我想要的吗?

【问题讨论】:

  • 好吧,我是 swift 新手……但我可以给你一个可以打印 foo 和 bar 的指针…… extension UseBProtocol { static func use(_ obj: T) { print(obj.foo) } 静态函数使用(_ obj: T) { print(obj.foo) print (obj.bar) } }
  • 我什至不知道 Swift,但我可以告诉你,仅使用方法签名可能是不可能的。你已经打破了 Liskov 替换原则:UseBProtocol 应该在 UseAProtocol 有效的地方有效,但 UseBProtocol 仅适用于 Bs,而 UseAProtocol 适用于所有 As。如果您翻转子类型并使UseAProtocol 成为UseBProtocol 的子类型,它将(可能)起作用。

标签: swift generics


【解决方案1】:

看起来您实际上正在寻找的是UseAProtocol 中的associatedType,而不是使use 函数通用。

通过在UseAProtocol 中声明关联类型并将use 的函数签名更改为static func use(_ obj: ProtocolType),您的代码可以正常编译,并且您可以从Manager 访问foobar

protocol AProtocol {
    var foo: String { get set }
}
protocol BProtocol: AProtocol {
    var bar: String { get set }
}

struct Test: BProtocol {
    var foo: String = "foo"
    var bar: String = "bar"
}

protocol UseAProtocol {
    associatedtype ProtocolType
    static func use(_ obj: ProtocolType)
}

protocol UseBProtocol: UseAProtocol {
}

extension UseBProtocol {
    static func use(_ obj: BProtocol) {
        print(obj.foo)
        print(obj.bar)
    }
}

struct Manager: UseBProtocol {
}

Manager.use(Test()) //prints both "foo" and "bar"

【讨论】:

  • 这几乎是我正在寻找的,但如果我尝试向相关类型添加一个约束,使其符合“A”或“B”,它将不符合。我添加了通用要求,因为我希望 UseAProtocol 仅使用 AProtocol 对象,而 UseBProtocol 仅使用 BProtocol(也是 AProtocol)对象。今天我在我的代码中使用了带有这样的约束的关联类型,但由于它是class 要求,我需要为这个“A:B”示例使用一个结构,为类似的层次结构“C:D”使用另一个单独的类,另一个用于一个'E:F'......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
相关资源
最近更新 更多