Swift Casting Generic to Optional with a nil value causes fatalError

♀尐吖头ヾ 提交于 2020-01-05 02:58:10

问题


Using Swift 2, in my contrived example I am converting a String to an Int or more specifically an Int or an Int? using a generic. In the case where the Int? should be nil the cast will fail with a fatalError: fatal error: unexpectedly found nil while unwrapping an Optional value

These look like they may be similar/duplicate questions:

  • Swift - casting a nil core data string as an optional value

  • Swift: detecting an unexpected nil value in a non-optional at runtime: casting as optional fails

My question is: how is one supposed to cast to an optional that is nil?

Example:

class Thing<T>{
    var item: T

    init(_ item: T){
        self.item = item
    }
}

struct Actions{

    static func convertIntForThing<T>(string: String, thing:Thing<T>) -> T{
        return convertStringToInt(string, to: T.self)
    }

    static func convertStringToInt<T>(string: String, to: T.Type) -> T{
        debugPrint("Converting to ---> \(to)")

        if T.self == Int.self{
            return Int(string)! as! T
        }

        // in the case of "" Int? will be nil, the cast
        // here causes it to blow up with:
        //
        // fatal error: unexpectedly found nil while unwrapping an
        // Optional value even though T in this case is an Optional<Int>
        return Int(string) as! T

    }
}


func testExample() {
    // this WORKS:
    let thing1 = Thing<Int>(0)
    thing1.item = Actions.convertIntForThing("1", thing: thing1)

    // This FAILS:
    // empty string  where value = Int("")
    // will return an Optional<Int> that will be nil
    let thing2 = Thing<Int?>(0)
    thing2.item = Actions.convertIntForThing("", thing: thing2)
}

testExample()

回答1:


You can't cast nil to some-kind-of-nil, but you can make some-kind-of-nil, as this artificial example shows:

    func test(s:String) -> Int? {
        var which : Bool { return Int(s) != nil }
        if which {
            return (Int(s)! as Int?)
        } else {
            return (Optional<Int>.None)
        }
    }

    print(test("12"))
    print(test("howdy"))



回答2:


I got something that does work.

I forgot that Optional is a NilLiteralConvertible. So we can provide 2 variations on the conversion function and it will not fail. Basically, provides a constraint on T where T: NilLiteralConvertible

class Thing<T>{
    var item: T

    init(_ item: T){
        self.item = item
    }
}

struct Actions{

    // Provide 2 variations one with T the other where T: NilLiteralConvertible
    // variation 1 for non-optionals
    static func convertIntForThing<T>(string: String, thing:Thing<T>) -> T{
        return convertStringToInt(string, to: T.self)
    }

    // variation 2 for optionals
    static func convertIntForThing<T where T: NilLiteralConvertible>(string: String, thing:Thing<T>) -> T{
        return convertStringToInt(string, to: T.self)
    }

    static func convertStringToInt<T>(string: String, to: T.Type) -> T{
        debugPrint("Converting to ---> \(to)")
        return Int(string)! as! T
    }

    static func convertStringToInt<T where T: NilLiteralConvertible>(string: String, to: T.Type) -> T{
        debugPrint("Converting to ---> \(to)")

        let value = Int(string)

        if let _ = value{
            return value as! T
        }

        let other: T = nil
        return other
    }
}

func testExample() {
    // this WORKS:
    let thing1 = Thing<Int>(0)
    thing1.item = Actions.convertIntForThing("1", thing: thing1)

    let thing2 = Thing<Int?>(0)
    thing2.item = Actions.convertIntForThing("", thing: thing2)
}

testExample()



回答3:


Generally casting in Swift has sometimes weird behaviors when you are working with generic types. A simple workaround would be to make a generic casting function:

func cast<T, U>(value: T, type: U.Type) -> U {
    return value as! U
}

Now you can rewrite the casting to:

return cast(Int(string), type: T.self)


来源:https://stackoverflow.com/questions/32232392/swift-casting-generic-to-optional-with-a-nil-value-causes-fatalerror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!