Swift元组到可选类型的赋值

13

我正在使用Swift编写一些代码来学习这门语言。这是我的基类:

import Foundation
class BaseCommand:NSOperation
{
    var status:Int? = nil
    var message:String? = nil

    func buildRequest() -> NSData?
    {
        return nil
    }

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

    override func main() {
        let requestBody = self.buildRequest()

        println("Sending body \(requestBody)")
        // do network op
        var networkResultBody = "test"

        var resultBody:NSData = networkResultBody.dataUsingEncoding(NSUTF8StringEncoding)!
        (self.status, self.message) = self.parseResponse(resultBody)
    }
}

问题出在最后一行:

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

编译器提示“无法将元组转换(Status:Int,Error:String)为(Int?,String?)”

我理解问题在于self.status和self.message是可选的,而parseResponse不返回可选项(我也不想这样做)。如何告诉它执行必要的赋值和转换,将数据放入实例变量中?

2个回答

6

另一个答案建议(在修改之前)只需执行以下操作:

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

我发现这段代码是不安全的。如果在赋值时self.statusself.messagenil,程序将会崩溃。在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()

以下是另一种可行的做法:
let (stat, err) = self.parseResponse(resultBody)
(self.status, self.error) = (Optional(stat), Optional(err))

或者,正如@AndriyGordiychuk发现的那样,它可以在没有Optional的情况下工作:

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

有趣的是,这样做可以起作用,但是分配函数结果却不行。


请注意以下实验:

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

看起来当元组文字被赋值给一个元组时,Swift会采取捷径,并不先构造元组。相反,它只是直接赋值给各个元素。

因此,这样的代码:

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

等同于:

i = 3
s = "hello"

这是因为你可以将 Int 赋值给一个 Int? 变量,将 String 赋值给一个 String? 变量。元组赋值失败,因为类型需要匹配。

1
你可以分解元组并重新构建它:(i,s)=(t.0,t.1) - brian.clear

3
您需要执行以下操作(不需要使用可选项):
let returnValue = self.parseResponse(resultBody)
(self.status,self.message) = (returnValue.Status,returnValue.Error)

如果self.statusself.message为空,您的第一个方法将会崩溃。 - vacawama
我已经测试过了,它不会崩溃。为什么会呢?只有在你将它们解包并分配给期望非空值的东西时,它才会崩溃。显式解包 nil 本身不会导致崩溃 ;) - Andriy Gordiychuk
请看我的回答。如果self.status或者self.messagenil,我的Playground测试在Xcode 6.4和7.0 beta 5中都会崩溃。 - vacawama
@vacawama 好的,你是对的。我把函数输出的打印与一切正常的标志混淆了。不过,仍然有一个更好的选择,就是可以省略Optional() ;) - Andriy Gordiychuk
给您最新回答点赞。 - vacawama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接