Swift Casting Generic to Optional with a zero value raises a fatalError

Using Swift 2, in my contrived example, do I convert String to Int or, more specifically, Int or Int? using generic. In the case when the value of Int? must be equal to nil, discarded with fatalError: fatal error: unexpectedly found nil while unwrapping an Optional value

Seems like they might be similar / repeating questions:

My question is: how should I transfer to an option that is zero?

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() 
+2
source share
3 answers

You cannot use nil for any level, but you can do something like zero, 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
source

I have something that really works.

I forgot that Optional is NilLiteralConvertible . Thus, we can provide 2 options for the conversion function, and this will not fail. Basically, there is a restriction 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() 
+2
source

As a rule, when using Swift it is sometimes strange when you work with generic types. A simple workaround would be to create a general cast 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) 
0
source

Source: https://habr.com/ru/post/1235861/


All Articles