如何将类型(例如String)作为函数参数传递?

时间:2016-02-13 22:06:42

标签: swift

我正在使用“JSON到我自己的班级”,我对类型转换感到非常头痛。典型的转换如下:

I need: "55" (JSON) -> 55 (Int)
My path: AnyObject? -> String -> Int

Swift没有直接将AnyObject(“55”)转换为Int(“55”),Swift认为“55”总是String。所以我写了辅助方法:

internal func jsonDirectToInt(from: AnyObject?) -> Int? {
    guard let string = from as? String,
        let int = Int(string) else { return nil }

    return int
}

我的问题:我可以将类型传递给函数作为参数,所以我可以这样写:

internal func jsonDirectToInt(from: AnyObject?, type: <T>) -> Int? {
    guard let string = from as? String,
        let int = <T>(string) else { return nil }

    return int
}

1 个答案:

答案 0 :(得分:1)

可能我误解了你想要实现的目标,但是从你的问题和随后的第三个代码块听起来你想要一个“jsonDirectToAnything”泛型函数;尝试使用from管道将JSON type参数转换为通过JSON (AnyObject) -> String -> SomeType参数传递的类型。在上面的代码示例(最后一个代码块)中,即使显示您希望进行一些通用Int转换(指定为返回类型),您的返回类型也会设置为<T>(string),因此我将假设使用返回类型Int不是你想要的,而是使用泛型返回类型(如果没有;这个问题对我来说真的没有意义)。

无论如何,对于技术讨论:你可以创建这样一个函数,其泛型返回类型被约束为符合协议的类型---比如StringInitializable ---包括一个(可用的)蓝图String个实例的初始化程序。您可以将希望能够使用“通用”jsonDirect方法的类型扩展到StringInitializable,如果需要,还可以实现协议蓝图的String初始化程序。在下面的示例中,我在init?(_ text: String)中使用了蓝图初始值设定项StringInitializable。这种可用的初始化器很容易本地可用于例如DoubleString类型,但需要实现(仅作为包装),例如将Int扩展到协议。

最后请注意,在我们继续之前,存在几个用于处理JSON数据到本机Swift类型转换的现有工具,例如

针对您的具体问题的示例解决方案:

/* Protocol with blueprint for failable initializer by String */
protocol StringInitializable {
    init?(_ text: String)
}

/* Extend type types you want to use "generically" in 'jsonDirect' method */
extension Double : StringInitializable { } // already has a 'init?(_ text: String)', OK
extension String : StringInitializable { } // already has a 'init?(_ text: String)', OK
extension Int : StringInitializable {      // point to 'init(_:radix:)' initializer
    init?(_ text: String) {
        guard let foo = Int.init(text, radix: 10) else {
            return nil
        }
        self = foo
    }
}

/* Your own class */
class MyClass: StringInitializable {
    let foo : Int?
    required init?(_ text: String) {
        foo = Int(text)
    }
}

/* jsonDirect for (attempted) type conversion from AnyObject to 
   generic type, where the latter is constrained to types conforming 
   to protocol 'StringInitializable' */
func jsonDirect<T: StringInitializable>(from: AnyObject?, toType _ : T.Type) -> T? {
    guard let foo = from as? String, let bar = T(foo) else {
        return nil
    }
    return bar
}

将JSON转换为IntDoubleString以及自定义类MyClass的示例用法:

/* Example usage */
var myJSONInt : AnyObject = "55"
var myJSONInvalidInt : AnyObject = "foo"
var myJSONDouble : AnyObject = "55.3"
var myJSONString : AnyObject = "Foo"

/* Attempt json -> specified type conversions */
let fooInt = jsonDirect(myJSONInt, toType: Int.self)
let fooMyClass = jsonDirect(myJSONInt, toType: MyClass.self)
let fooInvalidInt = jsonDirect(myJSONInvalidInt, toType: Int.self)
let fooDouble = jsonDirect(myJSONDouble, toType: Double.self)
let fooIntString = jsonDirect(myJSONInt, toType: String.self)

/* Results */
print(fooInt.dynamicType, ": value =", fooInt ?? "nil")
    // Optional<Int> : value = 55

print(fooMyClass.dynamicType, ": value =", fooMyClass?.foo ?? "nil")
    // Optional<MyClass> : value = 55

print(fooInvalidInt.dynamicType, ": value =", fooInvalidInt ?? "nil")
    // Optional<Int> : value = nil

print(fooDouble.dynamicType, ": value =", fooDouble ?? "nil")
    // Optional<Double> : value = 55.3

print(fooIntString.dynamicType, ": value =", fooIntString ?? "nil")
    // Optional<String> : value = 55