Swift之可選項

本文首發於個人我的博客git

定義

  • 可選項,通常也叫可選類型,它容許將值設置爲nil
  • 在類型名稱後面加個問號? 來定義一個可選項
var name: String? = "Jack"
name = nil


var age: Int? // 默認就是nil 
age = 10
age = nil

複製代碼

強制解包

  • 可選項是對其餘類型的一層包裝,能夠將它理解爲一個盒子
  • 若是爲nil,那麼它是個空盒子
  • 若是不爲nil,那麼盒子裏裝的是:被包裝類型的數據
var age: Int? // 默認就是nil 
age = 10
age = nil

複製代碼
  • 若是要從可選項中取出被包裝的數據(將盒子裏裝的東西取出來),須要使用感嘆號! 進行強制解包
var age: Int? = 10
let ageInt: Int = age!
ageInt += 10

複製代碼
  • 若是對值爲nil的可選項(空盒子)進行強制解包,將會產生運行時錯誤
var age: Int?
age!// 報錯:Fatal error: Unexpectedly found nil while unwrapping an Optional value

複製代碼

判斷可選項是否包含值

let number = Int("123")
if number != nil {
	print("字符串轉換整數成功:\(number!)") 
} else {
	print("字符串轉換整數失敗") 
}

// 字符串轉換整數成功:123

複製代碼

可選項綁定

  • 可使用可選項綁定來判斷可選項是否包含值
    • 若是包含就自動解包,把值賦給一個臨時的常量(let)或者變量(var),並返回true,不然返回false
if let number = Int("123") {
   print("字符串轉換整數成功:\(number)") 
    // number是強制解包以後的Int值
	// number做用域僅限於這個大括號
} else { 
	print("字符串轉換整數失敗")
}


// 字符串轉換整數成功:123
複製代碼

eg:github

enum Season : Int {
    case spring = 1, summer, autumn, winter
}
if let season = Season(rawValue: 6) {
	switch season { 
		case .spring:
        	print("the season is spring")
    	default:
        	print("the season is other")
    }
} else {
    print("no such season")
}


// no such season
複製代碼

等價寫法

可選項綁定中,若是多個條件好比下面spring

if let first = Int("4") {
    if let second = Int("42") {
        if first < second && second < 100 {
            print("\(first) < \(second) < 100")
			} 
		}
}
// 4 < 42 < 100

複製代碼

能夠用 , 分割開,看起來更簡單編程

if let first = Int("4"),
    let second = Int("42"),
    first < second && second < 100 {
    print("\(second) < \(second) < 100")
}
// 4 < 42 < 100

複製代碼

while循環中使用可選項綁定

  • 有以下需求 //遍歷數組,將遇到的正數都加起來,若是遇到負數或者非數字,中止遍歷
//遍歷數組,將遇到的正數都加起來,若是遇到負數或者非數字,中止遍歷
// var strs = ["10", "20", "abc", "-20", "30"]

var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
	sum += num
	index += 1 
}
	
print(sum)

複製代碼

空合併運算符 ??(Nil-Coalescing Operator)

eg:數組

public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
複製代碼
  • a ?? b
  • a 是可選項
  • b 是可選項 或者 不是可選項
  • b 跟 a 的存儲類型必須相同
  • 若是 a 不爲nil,就返回 a
  • 若是 a 爲nil,就返回 b
  • 若是 b 不是可選項,返回 a 時會自動解包

規律: 返回的類型取決於bbash

舉例以下:app

let a: Int? = 1
let b: Int? = 2
let c = a ?? b // c是Int? , Optional(1)
複製代碼
let a: Int? = 1
let b: Int = 2
let c = a ?? b // c是Int , 1
複製代碼
let a: Int? = nil
let b: Int = 2
let c = a ?? b // c是Int , 2
複製代碼
let a: Int? = nil
let b: Int? = 2
let c = a ?? b // c是Int? , Optional(2)
複製代碼
let a: Int? = nil 
let b: Int = 2
// 若是不使用??運算符 
let c: Int
if let tmp = a {
    c = tmp
} else { 
	c=b
}

// 使用 ?? 運算符
let c = a ?? b // c是Int? , nil
複製代碼

多個 ?? 一塊兒使用

let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 // c是Int , 1
複製代碼
let a: Int? = nil
let b: Int? = 2
let c = a ?? b ?? 3 // c是Int , 2
複製代碼
let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 3 // c是Int , 3
複製代碼

??跟if let配合使用

let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
	print(c) 
}
// 相似於if a != nil || b != nil
複製代碼
if let c = a, let d = b {
    print(c)
	print(d) 
}
// 相似於if a != nil && b != nil
複製代碼

guard語句

  • 當guard語句的條件爲false時,就會執行大括號裏面的代碼
  • 當guard語句的條件爲true時,就會跳過guard語句
  • guard語句特別適合用來「提早退出」
guard 條件 else {
// do something....
退出當前做用域
// returnbreakcontinue、throw error }
複製代碼
  • 當使用guard語句進行可選項綁定時,綁定的常量(let)、變量(var)也能在外層做用域中使用

假設咱們有個登錄的需求,要求輸入帳號,密碼。缺一不可。ui

用if語句書寫

//if語句實現登錄
func login(_ info: [String : String]) { 
	let username: String
	if let tmp = info["username"] {
        username = tmp
    } else {
		print("請輸入用戶名")
		return
	}
	
	let password: String
	if let tmp = info["password"] {
        password = tmp
    } else {
		print("請輸入密碼")
		return
	}
	
	// 能來到這裏,說明,username和password都是有值的
	// if username ....
	// if password ....
	print("用戶名:\(username)", "密碼:\(password)", "登錄ing")
}
 
// 調用
login(["username" : "jack", "password" : "123456"]) // 用戶名:jack 密碼:123456 登錄ing 

login(["password" : "123456"]) // 請輸入密碼

login(["username" : "jack"]) // 請輸入用戶名
複製代碼

若是用guard來書寫

func login(_ info: [String : String]) {
	guard let username = info["username"] else {
			print("請輸入用戶名")
			return
	}
	
	guard let password = info["password"] else {
			print("請輸入密碼")
			return
	}
	
	// if username ....
	// if password ....
	print("用戶名:\(username)", "密碼:\(password)", "登錄ing")
}

複製代碼

隱式解包(Implicitly Unwrapped Optional)

  • 在某些狀況下,可選項一旦被設定值以後,就會一直擁有值
  • 在這種狀況下,能夠去掉檢查,也沒必要每次訪問的時候都進行解包,由於它能肯定每次訪問的時候都有值
  • 能夠在類型後面加個感嘆號 ! 定義一個隱式解包的可選項
let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
    print(num1 + 6) // 16
}
if let num3 = num1 {
    print(num3) //10
}
複製代碼

注意不能設置爲nilspa

let num1: Int! = nil
// Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let num2: Int = num1

複製代碼

儘可能不要使用這個強制解包。 除非你設計接口,不但願接收空值,若是別人傳Nil過來,直接報錯設計

字符串插值

  • 可選項在字符串插值或者直接打印時,編譯器會發出警告
var age: Int? = 10
print("My age is \(age)")
複製代碼
  • 至少有3種方法消除警告
print("My age is \(age!)")
// My age is 10

 print("My age is \(String(describing: age))")
// My age is Optional(10)

 print("My age is \(age ?? 0)")
// My age is 10
複製代碼

多重可選項

  • 可使用lldb指令 frame variable –R 或者 fr v –R 查看區別
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10


print(num2 == num3) // true

複製代碼

還有下面這種

var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil


print(num2 == num3) // false
(num2 ?? 1) ?? 2 // 2
(num3 ?? 1) ?? 2 // 1

複製代碼

參考資料:

Swift官方源碼

從入門到精通Swift編程

相關文章
相關標籤/搜索