I have a Swift function that accepts Any and I want it to be able to accept an array of Strings, an array of Ints, a mixed array, or an array of arrays, etc. It also can accept just a String or an Int, etc, not in an array.
我有一个接受Any的Swift函数,我希望它能够接受一个字符串数组,一个Ints数组,一个混合数组或一个数组数组等。它也可以只接受一个String或一个Int,等,不在数组中。
So I have this:
所以我有这个:
private func parse(parameter: Any) {
if parameter is Int {
// Int
} else if (parameter is Float) || (parameter is Double) {
// Double
} else if parameter is String {
// String
} else if parameter is Bool {
// Bool
} else if let array = parameter as? [Any] {
// Should catch all Arrays
} else {
assert(false, "Unsupported type") // [String] ends up here
}
}
But if I call parse(["Strings"])
, the assert is raised. How can I catch all types of Arrays?
但是如果我调用parse([“Strings”]),则会引发断言。我怎样才能捕获所有类型的数组?
edit - there was some confusion as to what I'm trying to accomplish. I basically need to return a String based on the type, so Int -> "" and String -> "", so an array would make recursive calls to return "..."
编辑 - 对于我想要完成的事情存在一些困惑。我基本上需要根据类型返回一个String,所以Int - >“”和String - >“”,所以一个数组会使递归调用返回“...”
This post is marked as a duplicate, but that other question is about Javascript, not Swift.
这篇文章被标记为重复,但另一个问题是关于Javascript,而不是Swift。
4 个解决方案
#1
10
I finally found the way to do that, which is to use NSArray
for casting.
我终于找到了这样做的方法,即使用NSArray进行投射。
private func parse(x: Any) {
if let o = x as? [Any] {
println("[Any]")
}
if let o = x as? [AnyObject] {
println("[AnyObject]")
}
if let o = x as? NSArray {
println("NSArray")
}
}
let a: [Any] = ["bar"]
let b: [AnyObject] = ["bar"]
let c = ["foo", 3.14]
parse(a) // ==> [Any]
parse(b) // ==> [AnyObject], and also NSArray
parse(c) // ==> NSArray
It look so that an array containing values of Any
internally represented in NSArray
. (But should it be able to cast c
to [Any]
...? I'm suspecting it's a bug.)
它看起来是一个包含NSArray内部表示的Any值的数组。 (但它应该能够将c转换为[Any] ......?我怀疑这是一个bug。)
#2
2
One way you can do this is to separate the function out to two separate implementations (with the same name), one that takes anArray
and one for everything else. You'll also need to make them generic functions instead of using the Any
type. With that setup, Swift can use type inference to figure out the best function to call.
你可以做到这一点的一种方法是将函数分离出两个独立的实现(具有相同的名称),一个用于获取aAray,另一个用于其他所有实现。您还需要使它们成为通用函数,而不是使用Any类型。通过该设置,Swift可以使用类型推断来找出要调用的最佳函数。
I'd implement it something like this (I'm just println
ing the type to show where things end up):
我实现它是这样的(我只是打印类型来显示事情的结局):
func parse<T>(parameter: T) {
if parameter is Int {
println("Int")
} else if (parameter is Float) || (parameter is Double) {
println("Double")
} else if parameter is String {
println("String")
} else if parameter is Bool {
println("Bool")
} else {
assert(false, "Unsupported type")
}
}
func parse<T>(parameter: Array<T>) {
println("Array")
for element in parameter {
// Recursively parsing...
parse(element)
}
}
Then calling it like this:
然后像这样调用它:
parse(1) // Int
parse(0.1) // Double
parse("asdf") // String
parse(true) // Bool
parse(["asdf", "asdf"]) // Array -> String String
Outputs:
输出:
Int
Double
String
Bool
Array
String
String
#3
2
The key to understanding typing and type related issues in Swift is that all roads lead to protocols.
理解Swift中键入和类型相关问题的关键是所有道路都会导致协议。
The challenge of this problem is detecting any type of array, not just one concrete type. The OP's example failed because [Any] is not a base class or a generalized pattern of [String], that is to say, that (from what I can tell), in Swift [T] is not covariant on T. Beyond that, you cannot check for SequenceType or CollectionType since they have associated types (Generator.Element).
这个问题的挑战是检测任何类型的数组,而不仅仅是一种具体类型。 OP的例子失败了,因为[Any]不是基类或[String]的通用模式,也就是说,(我可以说),在Swift [T]中不是T的协变。除此之外,您无法检查SequenceType或CollectionType,因为它们具有关联类型(Generator.Element)。
The idiomatic solution is thus to use a marker protocol to indicate which types you want to match your criteria. As illustrated below, you achieve this by creating an empty protocol, and associating it with the types of interest.
因此,惯用的解决方案是使用标记协议来指示您希望与您的标准匹配的类型。如下图所示,您可以通过创建一个空协议并将其与感兴趣的类型相关联来实现此目的。
import Foundation
protocol NestedType {}
extension Array: NestedType {}
extension Set: NestedType {}
extension Dictionary: NestedType {}
extension NSSet: NestedType {}
protocol AnyTypeOfArray {}
extension Array: AnyTypeOfArray {}
extension NSArray: AnyTypeOfArray {}
protocol AnyTypeOfDictionary {}
extension Dictionary: AnyTypeOfDictionary {}
func printType(v:Any) {
if v is NestedType {
print("Detected a nested type")
}
if v is AnyTypeOfArray {
print("\t which is an array")
}
else if v is AnyTypeOfDictionary {
print("\t which is a dictionary")
}
}
printType([String:Int]())
printType([Int]())
printType(NSArray())
The output of which is:
其输出是:
Detected a nested type
which is a dictionary
Detected a nested type
which is an array
Detected a nested type
which is an array
#4
0
You can use the _stdlib_getTypeName
that returns the mangled type name for the given value.
您可以使用_stdlib_getTypeName返回给定值的受损类型名称。
For example:
例如:
var myString = "String"
var myInteger = 10
var myArray = [10,22]
var myDictionary = ["one": 1, "two": 2, "three": 3]
println("\(_stdlib_getTypeName(myString))")
println("\(_stdlib_getTypeName(myInteger))")
println("\(_stdlib_getTypeName(myArray))")
println("\(_stdlib_getTypeName(myDictionary))")
The result will be:
结果将是:
_TtSS // for String
_TtSi // for integer
_TtSa // for array
_TtVSs10Dictionary // for dictionary
#1
10
I finally found the way to do that, which is to use NSArray
for casting.
我终于找到了这样做的方法,即使用NSArray进行投射。
private func parse(x: Any) {
if let o = x as? [Any] {
println("[Any]")
}
if let o = x as? [AnyObject] {
println("[AnyObject]")
}
if let o = x as? NSArray {
println("NSArray")
}
}
let a: [Any] = ["bar"]
let b: [AnyObject] = ["bar"]
let c = ["foo", 3.14]
parse(a) // ==> [Any]
parse(b) // ==> [AnyObject], and also NSArray
parse(c) // ==> NSArray
It look so that an array containing values of Any
internally represented in NSArray
. (But should it be able to cast c
to [Any]
...? I'm suspecting it's a bug.)
它看起来是一个包含NSArray内部表示的Any值的数组。 (但它应该能够将c转换为[Any] ......?我怀疑这是一个bug。)
#2
2
One way you can do this is to separate the function out to two separate implementations (with the same name), one that takes anArray
and one for everything else. You'll also need to make them generic functions instead of using the Any
type. With that setup, Swift can use type inference to figure out the best function to call.
你可以做到这一点的一种方法是将函数分离出两个独立的实现(具有相同的名称),一个用于获取aAray,另一个用于其他所有实现。您还需要使它们成为通用函数,而不是使用Any类型。通过该设置,Swift可以使用类型推断来找出要调用的最佳函数。
I'd implement it something like this (I'm just println
ing the type to show where things end up):
我实现它是这样的(我只是打印类型来显示事情的结局):
func parse<T>(parameter: T) {
if parameter is Int {
println("Int")
} else if (parameter is Float) || (parameter is Double) {
println("Double")
} else if parameter is String {
println("String")
} else if parameter is Bool {
println("Bool")
} else {
assert(false, "Unsupported type")
}
}
func parse<T>(parameter: Array<T>) {
println("Array")
for element in parameter {
// Recursively parsing...
parse(element)
}
}
Then calling it like this:
然后像这样调用它:
parse(1) // Int
parse(0.1) // Double
parse("asdf") // String
parse(true) // Bool
parse(["asdf", "asdf"]) // Array -> String String
Outputs:
输出:
Int
Double
String
Bool
Array
String
String
#3
2
The key to understanding typing and type related issues in Swift is that all roads lead to protocols.
理解Swift中键入和类型相关问题的关键是所有道路都会导致协议。
The challenge of this problem is detecting any type of array, not just one concrete type. The OP's example failed because [Any] is not a base class or a generalized pattern of [String], that is to say, that (from what I can tell), in Swift [T] is not covariant on T. Beyond that, you cannot check for SequenceType or CollectionType since they have associated types (Generator.Element).
这个问题的挑战是检测任何类型的数组,而不仅仅是一种具体类型。 OP的例子失败了,因为[Any]不是基类或[String]的通用模式,也就是说,(我可以说),在Swift [T]中不是T的协变。除此之外,您无法检查SequenceType或CollectionType,因为它们具有关联类型(Generator.Element)。
The idiomatic solution is thus to use a marker protocol to indicate which types you want to match your criteria. As illustrated below, you achieve this by creating an empty protocol, and associating it with the types of interest.
因此,惯用的解决方案是使用标记协议来指示您希望与您的标准匹配的类型。如下图所示,您可以通过创建一个空协议并将其与感兴趣的类型相关联来实现此目的。
import Foundation
protocol NestedType {}
extension Array: NestedType {}
extension Set: NestedType {}
extension Dictionary: NestedType {}
extension NSSet: NestedType {}
protocol AnyTypeOfArray {}
extension Array: AnyTypeOfArray {}
extension NSArray: AnyTypeOfArray {}
protocol AnyTypeOfDictionary {}
extension Dictionary: AnyTypeOfDictionary {}
func printType(v:Any) {
if v is NestedType {
print("Detected a nested type")
}
if v is AnyTypeOfArray {
print("\t which is an array")
}
else if v is AnyTypeOfDictionary {
print("\t which is a dictionary")
}
}
printType([String:Int]())
printType([Int]())
printType(NSArray())
The output of which is:
其输出是:
Detected a nested type
which is a dictionary
Detected a nested type
which is an array
Detected a nested type
which is an array
#4
0
You can use the _stdlib_getTypeName
that returns the mangled type name for the given value.
您可以使用_stdlib_getTypeName返回给定值的受损类型名称。
For example:
例如:
var myString = "String"
var myInteger = 10
var myArray = [10,22]
var myDictionary = ["one": 1, "two": 2, "three": 3]
println("\(_stdlib_getTypeName(myString))")
println("\(_stdlib_getTypeName(myInteger))")
println("\(_stdlib_getTypeName(myArray))")
println("\(_stdlib_getTypeName(myDictionary))")
The result will be:
结果将是:
_TtSS // for String
_TtSi // for integer
_TtSa // for array
_TtVSs10Dictionary // for dictionary