类型转换和循环的位置

时间:2015-06-24 08:39:41

标签: swift swift2

我有以下情况:

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

3 个答案:

答案 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。我已经定义了相同的。