Swift tuple to Optional assignment

一笑奈何 提交于 2019-12-04 23:58:24

Another answer suggested (before it was changed) to just do:

(self.status!, self.message!) = self.parseResponse(resultBody)

I have found that is unsafe. It will crash if either self.status or self.message is nil at the time of the assignment. Try this test in a Playground:

class Test {
    var status: Int?
    var error: String?

    func parseResponse() -> (Status:Int, Error:String)
    {
        return (200, "Success")
    }

    func testIt() {
        (self.status!, self.error!) = parseResponse()
        print(self.status)
        print(self.error)
    }
}

let mytest = Test()
mytest.testIt()

Here is another way it could be done:

let (stat, err) = self.parseResponse(resultBody)
(self.status, self.error) = (Optional(stat), Optional(err))

or, as @AndriyGordiychuk discovered, it works without Optional:

let (stat, err) = self.parseResponse(resultBody)
(self.status, self.error) = (stat, err)

It's curious that that works, but assigning the result of the function does not.


Note the following experiment:

var i: Int?
var s: String?

// This works
(i, s) = (3, "hello")

// This fails with error: cannot express tuple conversion '(Int, String)' to '(Int?, String?)
let t = (3, "hello")
(i, s) = t

It seems that when the assignment is a tuple literal assigned to a tuple, Swift takes a shortcut and doesn't first construct the tuple. Instead, is just assigns the individual elements.

So this:

(i, s) = (3, "hello")

is equivalent to:

i = 3
s = "hello"

which works because you can assign an Int to an Int? variable and a String to a String? variable. The tuple assignment fails because the types need to match.

You have to do this (no optionals needed):

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