在 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
的元素上运行循环体,这些元素是UIButton
s,但没有帮助,例如在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 中进行类型转换
如何在此 for 循环中修复'无法将'String'类型的值转换为预期的参数类型'Int'
从浮点字符串到 Int 的 Python 类型转换在创建列表时无法在 for 循环中工作