Swift 1.2
我正在尝试在一个函数中切换案例中的匹配,该函数采用Any作为其参数的类型,以便分派给私有更专用的init。
这是一个Playground推断:
import Foundation
struct myStruct {
}
func switchOnAny(any: Any) -> String {
println("Dynamic Type == \(any.dynamicType)")
switch any {
case let array as [Any]:
return "Array"
case let array as NSArray:
return "NSArray"
default:
return "Default"
}
}
let emptyStringArray : [String] = []
let stringArray : [String] = ["Bob", "Roger"]
let intArray = [1, 2, 3]
let customStructArray : [myStruct] = []
println("\t\touput : \(switchOnAny([]))")
println("\t\touput : \(switchOnAny(emptyStringArray))")
println("\t\touput : \(switchOnAny(stringArray))")
println("\t\touput : \(switchOnAny(intArray))")
println("\t\touput : \(switchOnAny(customStructArray))")
产生以下输出:
动态类型== __NSArrayI
产量:NSArray
动态类型== Swift.Array
产量:NSArray
动态类型== Swift.Array
产量:NSArray
动态类型== Swift.Array
产量:NSArray
动态类型== Swift.Array< __ lldb_expr_37.myStruct>
输出:默认
我想知道为什么案例as [Any]
没有得到它,因为我从未请求过NSArray?
我可以假设任何类型的Swift数组都会进入NSArray案例,或者我需要编写2个case语句(一个用于NSArray,一个用于[Any])以覆盖我的背部(显然会有需要)?
在进行了一些测试之后,我可以看到,当我提供一个自定义结构的数组时,没有任何模式匹配。我需要像[myStruct]这样的匹配才能识别。这正是我想要避免的,因为它只是我可以接受的选项之一。
为了提供更多上下文,我将我的项目放在Github上:https://github.com/VinceBurn/SwiftyPlist/tree/test/init-Any。 该项目是关于TDD并将属性列表表示为可以通过下标访问的类似树的结构树。 (比如SwiftyJSON)
答案 0 :(得分:3)
在 Swift 1.2:
中,最可靠地决定变量是否是任何类型的数组都是使用反射let array = []
let mirror = reflect(array)
let isArray = mirror.disposition == MirrorDisposition.IndexContainer
和 Swift 2.0:
let anArray = []
let mirror = Mirror(reflecting: anArray)
let isArray = mirror.displayStyle == .Collection
只是出于好奇,看看这些枚举很有意思:
enum MirrorDisposition { //Swift 1.2
case Struct
case Class
case Enum
case Tuple
case Aggregate
case IndexContainer
case KeyContainer
case MembershipContainer
case Container
case Optional
case ObjCObject
}
enum DisplayStyle { //Swift 2.0
case Struct
case Class
case Enum
case Tuple
case Optional
case Collection
case Dictionary
case Set
}
<强>已更新强> 这是一个完整的模式匹配示例:
func switchOnAny(any: Any) -> String {
println("Dynamic Type == \(any.dynamicType)")
switch any {
case let array as Any where reflect(any).disposition == MirrorDisposition.IndexContainer:
return "Any kind of array"
default:
return "Default"
}
}
答案 1 :(得分:2)
不幸的是,尚未完全支持像Array
这样的泛型类型之间的转换。即使你想要上传也有奇怪的情况:
let emptyStringArray : [String] = []
emptyStringArray as [Any] // succeeds
let stringArray : [String] = ["Bob", "Roger"]
stringArray as [Any] // error! due to the elements?!
let intArray = [1, 2, 3]
intArray as [Any] // error
let customStructArray : [myStruct] = []
customStructArray as [Any] // '[myStruct]' is not convertible to '[Any]'
没有使用协议也没有好的解决方法。如果您真的想拥有这种动态行为,可以使用reflect()
函数的反射。在Swift 2中,它们更强大,但它仍然不是一个好的解决方案。
修改强>
所有Arrays
通过扩展程序采用的协议解决方案(仅适用于您的具体情况):
protocol ArrayType {
var anyValues: [Any] { get }
}
extension Array: ArrayType {
var anyValues: [Any] {
return self.map { $0 as Any }
}
}
// now the switch gets rewritten as
switch any {
case let array as ArrayType:
let anyArray = array.anyValues
return "Array"
case let array as NSArray:
return "NSArray"
default:
return "Default"
}
答案 2 :(得分:1)
我建议使用自定义协议扩展Array
类型,您可以使用它来检查它:
protocol ArrayType {}
extension Array : ArrayType {}
然后你可以这样做:
let array : Any = [1, 2, 3, 4]
array is ArrayType // true
另请查看我的其他答案here。
但实际上你看起来并不想拥有一个以Any
作为参数的公共初始化器(你很少想要它),而是两个不同的初始化器,一个用于数组,一个非数组,如:
class MyClass {
init<T>(array: [T]) {
}
init<T>(nonArray: T) {
}
}
答案 3 :(得分:0)
结论:在Swift 1.2中
在Kametrixom和Daniel Nagy回答的情况下,可以为所有类型的阵列输入一个开关盒。总而言之,我留下了2个案例陈述,一个
case let array as NSArray:
return "NSArray"
case let array as [myStruct]:
return "myStruct array"