在 for-in 循环中进行类型转换

Posted

技术标签:

【中文标题】在 for-in 循环中进行类型转换【英文标题】:Type casting in for-in loop 【发布时间】:2014-11-22 11:32:25 【问题描述】:

我有这个 for-in 循环:

for button in view.subviews 

现在我希望将按钮转换为自定义类,以便我可以使用它的属性。

我试过这个:for button in view.subviews as AClass

但它不起作用并给我一个错误:'AClass' does not conform to protocol 'SequenceType'

我试过这个:for button:AClass in view.subviews

但这也不管用。

【问题讨论】:

for button in view.subviews as [AClass]怎么样 哈哈我没有想到,当然最好将数组转换为AClass数组,谢谢。您可以对此做出回答,以便我可以给您一些代表:) 比较***.com/questions/25097958/…. 【参考方案1】:

对于 Swift 2 及更高版本:

Swift 2 将 case 模式 添加到 for 循环中,这使得在 for 循环中进行类型转换更加容易和安全:

for case let button as AClass in view.subviews 
    // do something with button

为什么这比您在 Swift 1.2 及更早版本中所做的更好?因为 案例模式 允许您从集合中选择您的特定类型。它只匹配您要查找的类型,因此如果您的数组包含混合,您只能对特定类型进行操作。

例如:

let array: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for case let str as String in array 
    print(str)

输出:

Hello
World!

对于 Swift 1.2

在这种情况下,您正在转换 view.subviews 而不是 button,因此您需要将其向下转换为所需类型的数组:

for button in view.subviews as! [AClass] 
    // do something with button

注意:如果底层数组类型不是[AClass],则会崩溃。这就是as! 上的! 告诉你的。如果您不确定类型,您可以使用条件转换 as? 以及可选绑定 if let

if let subviews = view.subviews as? [AClass] 
    // If we get here, then subviews is of type [AClass]
    for button in subviews 
        // do something with button
    

对于 Swift 1.1 及更早版本:

for button in view.subviews as [AClass] 
    // do something with button

注意:如果子视图的类型不是AClass,这也会崩溃。上面列出的安全方法也适用于早期版本的 Swift。

【讨论】:

只是给像我这样一开始没有得到它的其他人的注释 - 类名必须放在 [ ] 括号内,就像在这个例子中一样。也许只有我一个人,但起初我认为这只是代码示例中的一种格式选择:) 我认为这是因为我们正在转换为一个数组。 @kmcgrady 它只是[Class] 看起来比Array<Class> 好多了。 那么出于好奇,有没有办法在 for 循环中执行多个 case 语句?例如,如果我想对按钮做一件事,对文本字段做另一件事?【参考方案2】:

这个选项更安全:

for case let button as AClass in view.subviews 

或快速的方式:

view.subviews
  .compactMap  $0 as AClass 
  .forEach  .... 

【讨论】:

【参考方案3】:

提供的答案是正确的,我只是想添加这个作为补充。

使用强制转换的 for 循环时,代码会崩溃(正如其他人已经提到的那样)。

for button in view.subviews as! [AClass] 
    // do something with button

但不是使用 if 子句,

if let subviews = view.subviews as? [AClass] 
    // If we get here, then subviews is of type [AClass]
    ...

另一种方法是使用while循环:

/* If you need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let (index, subview) = iterator.next() as? (Int, AClass) 
    // Use the subview
    // ...


/* If you don't need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let subview = iterator.next().element as? AClass 
    // Use the subview
    // ...

如果数组的某些元素(但不是全部)可能是AClass 类型,这似乎更方便。

虽然现在(从 Swift 5 开始),我还是会选择 for-case 循环:

for case let (index, subview as AClass) in view.subviews.enumerated() 
    // ...


for case let subview as AClass in view.subviews 
    // ...

【讨论】:

这里只是一个疑问......快速枚举函数是否在这里执行迭代/循环......只是认为重构会失去性能不会很好......谢谢【参考方案4】:

您也可以使用where 子句

for button in view.subviews where button is UIButton 
    ...

【讨论】:

where 子句是一个布尔守卫,但不会在循环体内强制转换 button 的类型,这是其他解决方案的目标。所以这只会在view.subviews 的元素上运行循环体,这些元素是UIButtons,但没有帮助,例如在button 上调用AClass 特定的方法。 @JohnWhitley 你说得对,where 只守卫不施放。 where 对于只需要一个布尔值守卫的情况(双关语无意)可能更优雅和可读。【参考方案5】:

vacawama 提供的答案在 Swift 1.0 中是正确的。并且不再适用于 Swift 2.0。

如果你尝试,你会得到一个类似的错误:

'[AnyObject]' 不能转换为'[AClass]';

在 Swift 2.0 中你需要这样写:

for button in view.subviews as! [AClass]


【讨论】:

【参考方案6】:

您可以同时执行投射并确保安全:

for button in view.subviews.compactMap( $0 as? AClass ) 


【讨论】:

【参考方案7】:

如果你想在你的循环中有一个索引

for case let (index, button as AClass) in view.subviews.enumerated() 

【讨论】:

以上是关于在 for-in 循环中进行类型转换的主要内容,如果未能解决你的问题,请参考以下文章

Pyspark - 循环通过 structType 和 ArrayType 在 structfield 中进行类型转换

Python 字符串类型列表转换成真正列表类型

如何在此 for 循环中修复'无法将'String'类型的值转换为预期的参数类型'Int'

从浮点字符串到 Int 的 Python 类型转换在创建列表时无法在 for 循环中工作

JavaScript里的循环方法之forEach,for-in,for-of

请教java List 泛型转换