可选类型

木木木大约 4 分钟iOSSwift语法

可选类型

处理丢失数据

使用Int等类型来保整数。但是,如果想为用户存储age属性,如果你不知道某人的年龄,你会怎么做? 或许可以使用1000或-1等特殊数字来表示“未知”,这两个数字都是不可能的年龄,但真的会记得它使用的所有地方的这个数字吗? Swift的解决方案是可选类型,可以制作任何类型的可选类型。可选整数可能有一个像0或40这样的数字,但可能根本没有值——nil。 要使类型可选,请在它后面添加一个问号:

var age: Int? = nil

可选类型解包

可选字符串可能包含像“你好”这样的字符串,或者它们可能是nil

var name: String? = nil

如果使用name.count会发生什么?真实字符串有一个count属性,但nil是空的内存,没有count。 因此,尝试读取name.count是不安全的,Swift不允许这样做。所以必须查看可选的内部。 解包可选类型的常见方法是使用if let语法,如果可选类型内有值,那么可以使用,但如果没有,条件就会失败。

if let unwrapped = name {
    print("\(unwrapped.count) letters")
} else {
    print("Missing name.")
}

guard let

guard let 解包可选类型,如果里面发现nil,它期望退出使用的函数、循环或条件。 使用guard let允许在功能开始时处理问题,然后立即return。

func greet(_ name: String?) {
    guard let unwrapped = name else {
        print("You didn't provide a name!")
        return
    }
    print("Hello, \(unwrapped)!")
}

强制解包

可选类型表示可能存在或不存在的数据,但有时可以确保值不是nil。 在这些情况下,Swift允许您强制解包可选:将其从可选类型转换为非可选类型。

let str = "5"
let num = Int(str)

这使得num成为可选的Int,可以通过强制解包结果!:

let num = Int(str)!

只有当确定是安全的时才应该强制解包——这是它通常被称为崩溃操作员的原因。

隐式拆包可选类型

与常规可选件一样,隐式未包装的可选件可能包含一个值,或者它们可能为nil。无需拆开包装即可使用,当做不是可选类型来使用。如果是nil代码就会崩溃。 通过在类型名称后添加感叹号来创建隐式拆包可选类型:

let age: Int! = nil

nil 合并解包

这是一个接受整数作为其唯一参数并返回可选字符串的函数:

func username(for id: Int) -> String? {
    if id == 1 {
        return "Taylor Swift"
    } else {
        return nil
    }
}

如果用id15调用将返回nil,因为不被识别,但通过nil合并可以提供“匿名”的默认值:

let user = username(for: 15) ?? "Anonymous"

可选类型链

当使用可选时,Swift提供了一个快捷方式:如果访问像a.b.c和b是可选的,可以在它后面写一个问号以启用可选链接:a.b?.c。 代码运行时Swift将检查b是否有值,如果为nil则忽略行的其余部分——Swift将立即返回nil。但如果有值,将被解包并继续执行。

let names = ["John", "Paul", "George", "Ringo"]

使用数组first属性,如果数组有first项则返回第一个名称,如果数组为空则返回nil。然后可以在结果上调用uppercased()以使其成为大写字符串:

let beatle = names.first?.uppercased()

抛出函数的try

运行一个抛出函数,使用do、try和catch优雅地处理错误:

enum PasswordError: Error {
    case obvious
}

func checkPassword(_ password: String) throws -> Bool {
    if password == "password" {
        throw PasswordError.obvious
    }

    return true
}

do {
    try checkPassword("password")
    print("That password is good!")
} catch {
    print("You can't use that password.")
}

有两种选择可以try,既然你理解了可选的选项并强制解包,这两种选择都会更有意义。

  • try? 抛出函数更改为返回可选函数的函数。如果函数抛出错误,将收到nil作为结果,否则将获得作为可选包装的返回值:
if let result = try? checkPassword("password") {
    print("Result was \(result)")
} else {
    print("D'oh.")
}
  • try! 当您确定该功能不会失败时可以使用它。如果函数确实抛出错误代码将崩溃。
try! checkPassword("sekrit")
print("OK!")

可失败的初始化

一个可能成功或可能失败的初始化器。可以使用init?()在结构和类中编写这些而不是init()。如果出现问题,则返回nil。然后,返回值将是类型的可选值,可以随心所欲地解包。

struct Person {
    var id: String

    init?(id: String) {
        if id.count == 9 {
            self.id = id
        } else {
            return nil
        }
    }
}

类型选择 (Typecasting)

这里有三类:

class Animal { }
class Fish: Animal { }

class Dog: Animal {
    func makeNoise() {
        print("Woof!")
    }
}

创建几条鱼和几条狗,并将它们放入一个数组: 这里有三类:

let pets = [Fish(), Dog(), Fish(), Dog()]

在pets数组上循环并执行makeNoise函数,需要执行类型转换:Swift将检查每个对象是否是Dog对象,如果是可以调用makeNoise() 这使用了一个名为as?的新关键字,该关键字返回一个可选类型:如果类型转换失败,则为nil:

for pet in pets {
    if let dog = pet as? Dog {
        dog.makeNoise()
    }
}
上次编辑于:
贡献者: perhapsdone