我正在尝试编写一个无论对象类型如何都可以转换输入的函数。
示例用例可能类似于:
// Example 1, Strings
In: ("foo", "bar")
Out: "foobar"
// Example 2, Integers
In: (5, 10)
Out: 15
// Example 3, Mixed (String, Array)
In: ("baz", ["foo", "bar"])
Out: ["foo", "bar", "baz"]
我解决这个问题的方法是创建一个接受泛型类型的函数,然后通过一个开关运行它们来检测它们是哪种类型,然后相应地处理它们。
该功能看起来像这样
func process<T:Hashable,U> (lhs: T, rhs: U) -> U {
switch _stdlib_getTypeName(right) {
case "_TtSS": // string
// process
case "_TtSa": // array
// process
case "_TtVSs10Dictionary": // dictionary
// process
default:
println(_stdlib_getTypeName(rhs))
return rhs
}
现在,上面的代码都没有涉及我的问题,但我决定将其包含在分析中,因为我可能没有以正确的方式解决我的问题。我在某处读到“如果你正在检查泛型类型的类型,你就不应该使用泛型类型。”这听起来很准确。
我一直想知道是否可能更好地使用一个字典,其中键设置为一个类型(_TtSS for String)和一个函数作为它的值。然后使用functions[_stdlib_getTypeName(right)]()
运行通用变量的相应函数。但是,这仍然是检查泛型类型的类型。
所以现在我已经到了原来的问题,在我的case
s中查找字符串和数组,我可以使用{{1}来访问特定于类的函数}或(right as String)
。但是,当我尝试运行(right as Array)
时,我遇到了错误,(right as Dictionary)
产生错误时的输入是error: 'U' is not convertible to 'Dictionary<Key, Value>'
。无论密钥是["foo": "bar", "baz": "qux"]
还是Int
。
知道会导致什么原因吗?
答案 0 :(得分:0)
您可以为每个具有真实实现的类型构建一个专门的实例,而不是构建一个switch语句。
如果你需要一个基础(默认情况),它应该做什么,这很重要。您的选择是:
nil!
- 然后其他所有内容都必须明确解包。如果程序失败,这将导致程序在运行时断言。虽然这是我在下面选择的,但它不一定是最佳途径。nil?
- 然后其他所有内容都必须手动解包。这将导致编译器坚持程序员处理nil case。process
函数。lhs
而不附加lhs
设置一个特殊的基本案例,其中rhs
未明确支持。lhs
如果你有一组实现基本相同的类,我们可以使用协议来快捷。 Double
,String
和Array
的示例使用此策略。
// default case. Can be elided, return nil, or fatalError. I'm returning nil.
func process<T,U>(var lhs:T,rhs:U) -> T! {
return nil // nil! will cause consuming code to assert unless they explicitly check
}
// explicit case for array + member
func process<T>(var lhs:[T],rhs:T) -> [T]! {
lhs.append(rhs)
return lhs
}
// explicit case for dictionary + tuple
func process<K:Hashable,V>(var lhs:[K:V],rhs:(K,V)) -> [K:V] {
lhs[rhs.0] = rhs.1
return lhs
}
protocol AAA {
func +(lhs: Self, rhs: Self) -> Self
}
// case to handle the + protocol variant
func process<T:AAA>(lhs:T,rhs:T) -> T! {
return lhs + rhs
}
// indicate already conforming classes
extension Double:AAA {}
extension Int:AAA {}
extension Array:AAA {}
extension String:AAA {}
process("a", "b") // -> "ab"
process(["a"], "b") // -> ["a","b"]
process(["a"], ["b"]) // -> ["a","b"]
process(1,3) // -> 4
process(1.0,3.0) // nil - no implementation
process(NSDate(),"grr") // nil - no implementation
process(["a":1],("b",2)) // ["a":1,"b":2]
如果你想要一个中缀操作符而不是一个函数(如你的注释中所建议的那样,只需添加操作符声明:
infix operator +++ {}
然后用运算符替换process
的所有实例,例如+++
,然后按如下方式调用它:
[1,2,3] +++ 1
[1,2,3] +++ [4]
1 +++ 9
等
答案 1 :(得分:0)
在我的另一个答案中,我列出了泛型的案例,但还有另一种方法,使用switch downcasting:
这里我们感兴趣的是表达两种类型组合的输出。
switch语句可以为我们处理类型匹配:
func process2<T:Any,U:Any>(var _lhs: T, _rhs: U) -> T {
switch (_lhs, _rhs) {
case (var lhs as String, let rhs as String): // string
return lhs + rhs as T
case (var lhs as Array<U>, let rhs): // array
lhs.append(rhs)
return lhs as T
case let (lhs as Double, rhs as Double):
return lhs + rhs as T
case let (lhs as Int, rhs as Int):
return lhs + rhs as T
default:
println("default case")
return _lhs
}
}
所以让我们使用它:
process2(["foo"],"bar") // ["foo","bar"]
process2(1.0,2.0) // 3.0
process2("a","b") // "ab"
process2(1,2) // 3
我还没有找到如何做数组+数组或字典+任何东西