类型转换和 for 循环中的位置
Typecasting and where in for loop
我有以下场景:
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
我不是 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 {
}
compiles, but b is typed as A, not B
这就是我不明白的地方。很可能是因为我很笨。但是按照我的阅读方式,您的 protocolB 对象也符合定义的 protocolA。我的定义也是一样的。
还有 for case
(与 switch
语句中的 case
几乎相同)所以它看起来像这样:
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>
}
因此您可以同时使用两种协议的方法、属性等
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
相关的逻辑包含在该类型的定义中)
我不确定这是否适用于您的特定用例,但我认为它通常是一种更好的模式。
我有以下场景:
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
我不是 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 {
}
compiles, but b is typed as A, not B
这就是我不明白的地方。很可能是因为我很笨。但是按照我的阅读方式,您的 protocolB 对象也符合定义的 protocolA。我的定义也是一样的。
还有 for case
(与 switch
语句中的 case
几乎相同)所以它看起来像这样:
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>
}
因此您可以同时使用两种协议的方法、属性等
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
相关的逻辑包含在该类型的定义中)
我不确定这是否适用于您的特定用例,但我认为它通常是一种更好的模式。