我想做的事情有点复杂,请原谅所有的变量名。
目前我一直在做一些像
enum Foo {
enum Bar {
case prop11
case prop12
case prop13
// etc
}
enum Baz {
case prop21
case prop22
case prop23
// etc
}
}
protocol Fum1 {
var zot: Foo.Bar { get set }
}
protocol Fum2 {
var zot: Foo.Baz { get set }
}
struct Grunt1: Fum1 {
// code
}
struct Grunt2: Fum2 {
// code
}
这导致我复制了很多代码。因为相同的函数可以(在大多数情况下)在Grunt1
或Grunt2
上运行,并且我必须一直使用这样的东西来指定
protocol Bletch {
func doSomething(to grunt: Grunt1)
func doSomething(to grunt: Grunt2)
}
但是这两个函数的实现是相同的。这很令人沮丧。我想做一些像
protocol Fum {
associatedType Thud
var zot: Thud { get set }
}
struct Grunt<T: Foo>: Fum {
typealias Thud = T
}
接下来我要做的是
let grunt1 = Grunt<Foo.Bar>(zot: .prop11) //Autocompletes to .prop11, .prop12, .prop13
let grunt2 = Grunt<Foo.Baz>(zot: .prop23) //Autocompletes to .prop23, .prop22, .prop23
然后我可以这样写
protocol Bletch {
func doSomething(to grunt: Fum) // or (any Fum), whichever doesn't throw errors.
}
但是这不起作用,有没有别的方法可以得到我想要的结果?我只是想减少重复的代码。
你所描述的大部分已经工作,除了<T: Foo>
,因为Foo
不是一个协议。
不让Foo.Bar
和Foo.Baz
嵌套类型,可以让Foo
成为一个协议,让Bar
和Baz
都采用该协议。(为什么它们是嵌套类型呢?):
protocol Foo {}
enum Bar : Foo { /* cases */ }
enum Baz : Foo { /* cases */ }
如果这不是一个选项,你也可以扩展Foo.Bar
和Foo.Baz
,让它们都采用一个共同的协议:
protocol FooProtocol {}
extension Foo.Bar : FooProtocol {}
extension Foo.Baz : FooProtocol {}
现在你只需要将Grunt
上的通用T
约束为FooProtocol
而不是Foo
:
struct Grunt<T: FooProtocol>: Fum {
typealias Thud = T
var zot: Thud
}