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()
。我终于明白了。谢谢你坚持我。这假设该方法对所有形状都有意义。例如,如果要计算形状
数组中所有圆的平均半径,您会怎么做?如果需要执行依赖于同质的操作,我不会在数组中存储异质类型。例如,您可以拥有一个单独的圆
数组,并将形状
作为一个计算属性。因此,每次需要所有形状的列表时,都会实例化一个新数组?是的,但如果存在性能问题,则很容易缓存它。