我有以下情况:
protocol A {}
protocol B: A {}
protocol C: A {}
let objects: [A] = ...
如何遍历数组并仅为B
类型的对象执行逻辑?
现在,我正在做这样的事情:
for object in objects {
if let b = object as? B {
...
}
}
但我想知道我是否可以使用where
来使这更具表现力和优雅。
for b in objects where b is B // <- compiles, but b is typed as A, not B
for b: B in objects where b is B // <- doesn't compile
for b in objects as! [B] where b is B // <- I get a warning that "is" will always be true
答案 0 :(得分:8)
还有for case
(与case
语句中的switch
几乎相同)所以它看起来像这样:
for case let b as B in objects {
// use b which is now of type B
}
另一个很好的表达方式是:
for case let b as protocol<B, C> in objects {
// use b which is now of type protocol<B, C>
}
因此您可以同时使用两种协议中的方法,属性等
答案 1 :(得分:2)
as? subtype
及其变体是代码气味。这里的其他答案将帮助您完成您想要的任务,但我想建议您将此逻辑从for
循环移至协议(如果可能的话)。
例如,考虑一个Shape
协议:
protocol Shape {
func draw()
func executeSomeSpecialOperation()
}
extension Shape {
func executeSomeSpecialOperation() {
// do nothing by default
}
}
创建符合它的三种形状类型:
struct Circle : Shape {
func draw() {
// drawing code goes here
}
}
struct Diamond : Shape {
func draw() {
// drawing code goes here
}
}
struct Pentagon : Shape {
func draw() {
// drawing code goes here
}
func executeSomeSpecialOperation() {
print("I'm a pentagon!")
}
}
如您所知,您可以创建一个形状数组:
let shapes : [Shape] = [Circle(), Diamond(), Pentagon()]
这种方法允许您在不知道其类型的情况下遍历此数组:
for shape in shapes {
shape.draw()
shape.executeSomeSpecialOperation()
}
这有两个好处:
for
循环的方法不需要知道Pentagon
是什么)Pentagon
相关的逻辑包含在该类型的定义中)我不确定这会对您的具体用例有效,但我认为这是一种更好的模式。
答案 2 :(得分:0)
我并不是100%肯定这会回答你的情况 - 因为你已经有类似的东西了 - 我并不完全理解你对你的版本不喜欢什么。但是这适用于Swift 2:
for object in objectArray where object is protocolB {
//print(object) // only objects conforming to protocolB
}
以下是我的声明:
var objectArray: [AnyObject] = []
// contains a mix of objects of the following 3 classes
class class01: protocolA {
}
class class02: protocolA, protocolB {
func test() -> String {
// required to conform to protocolB
return "hello"
}
}
class class03: protocolA, protocolB, protocolC {
func test() -> String {
// required to conform to protocolB
return "hello"
}
}
protocol protocolA {
}
protocol protocolB: protocolA {
func test() -> String
}
protocol protocolC: protocolA {
}
编译,但b键入A,而不是B
这是我不明白的一点。很可能是因为我愚蠢。但是我读这个的方式,你的protocolB对象也符合定义的protocolA。我已经定义了相同的。