Swift 类型转换和for循环中的位置

Swift 类型转换和for循环中的位置,swift,swift2,Swift,Swift2,我有以下情况: protocol A {} protocol B: A {} protocol C: A {} let objects: [A] = ... 如何在数组中循环并仅对B类型的对象执行逻辑 现在,我正在做这样的事情: for object in objects { if let b = object as? B { ... } } for case let b as B in objects { // use b which is now o

我有以下情况:

protocol A {}
protocol B: A {}
protocol C: A {}

let objects: [A] = ...
如何在数组中循环并仅对
B
类型的对象执行逻辑

现在,我正在做这样的事情:

for object in objects {
    if let b = object as? B {
        ...
    }
}
for case let b as B in objects {
  // use b which is now of type 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

对于b为b的对象中的b/我不能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的定义。我对我的定义是相同的。

还有
用于case
(几乎与
switch
语句中的
case
相同),因此它看起来是这样的:

for object in objects {
    if let b = object as? B {
        ...
    }
}
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>
}
对于case let b作为对象中的协议{
//使用现在属于协议类型的b
}

因此,您可以同时使用这两个协议中的方法、属性等作为?子类型及其变体是一种代码气味。这里的其他答案将帮助您实现所需,但我想建议您将此逻辑从
for
循环移动到协议(如果可能的话)

例如,考虑<代码>形状<代码>协议:

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
    循环的方法不需要知道
    五角大楼是什么)
  • 增加内聚性(与
    五角大楼相关的逻辑包含在该类型的定义中)

我不确定这是否适用于您的特定用例,但我认为这通常是一种更好的模式。

如果
protocolB
将定义一个函数
test()
,您将无法在迭代中对
object
调用它,而不将
object
类型转换为
protocolB
,因为
object
属于
AnyObject
类型,而不是
protocolB
类型。在更新的代码中,如果您尝试在注释的循环中调用
print(object.test())
,您将得到一个错误('AnyObject'没有名为'test()'的成员)。它在Xcode7中工作完全正常。包括打印(对象)
。这只是因为它是一个,例如,
print(object)
当然有效,因为
print()
确实接受了
AnyObject
参数
print(object.test())
不会,因为
test()
没有在
AnyObject
上定义。关键是你不能在
对象上调用
test()
,也不是说你不能打印
对象
,在你的例子中你从来没有调用过
test()
。我终于明白了。谢谢你坚持我。这假设该方法对所有
形状都有意义。例如,如果要计算
形状
数组中所有圆的平均半径,您会怎么做?如果需要执行依赖于同质的操作,我不会在数组中存储异质类型。例如,您可以拥有一个单独的
数组,并将
形状
作为一个计算属性。因此,每次需要所有形状的列表时,都会实例化一个新数组?是的,但如果存在性能问题,则很容易缓存它。