Swift之旅_Language Guide1

weixin_33797791發表於2018-04-21

最近抽空閱讀了swift官方文件的Language Guide部分小節,下面記錄一些知識盲點和個人認為比較有用的東西。


The Basics

第一個小節主要講解了一些基本的東西,如var let等。也有一些知識點可以記錄一下吧。

  • typealias

相當於oc裡的tyepdef吧,可以用來取別名。

typealias AudioSample = UInt16
  • optional & nil

Swift’s nil isn’t the same as nil in Objective-C. In Objective-C, nil is a pointer to a nonexistent object. In Swift, nil isn’t a pointer—it’s the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.

大概的意思是說oc裡的nil是指向了一個不存在的物件,而在swift中,nil不是指標,它是一個確定型別的缺失(= =蹩腳的英文),任何可選型別可以設定成nil,不只是物件型別。網上也有很多資料都介紹過可選型別,可選其實就是對某個型別進行了一層包裝,裡面包含了some和none,none就是這個nil,some就是具體的值。

  • assert:斷言

大部分用來除錯使用,類似guard,但是不符合條件程式會直接退出。

let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
  • Error handle

異常處理,不過目前只在呼叫別人的api的時候用到過= =。

do {
    try caThrowAnError(age: 1000)
} catch AgeEorror.negative {
    print(AgeEorror.negative.rawValue)
} catch AgeEorror.tooLarge {
    print(AgeEorror.tooLarge.rawValue)
} catch {
    print("未知錯誤~")
}
enum AgeEorror: String, Error {
    case negative = "輸入的年齡不能是負數!"
    case tooLarge = "不可能活那麼久!"
}
func caThrowAnError(age: Int) throws {
    if age < 0 {
        throw AgeEorror.negative
    } else if age > 200 {
        throw AgeEorror.tooLarge
    }
}

這裡結合列舉使用,丟擲的錯誤型別必須遵循Error協議。


Basic Operators

這一小節比較簡單,講解了大部分操作符。相信有點程式設計基礎的應該都會一眼帶過,但也抽兩個知識點意思意思吧!

  • ??

這個操作符在平時開發中使用還是非常頻繁的,至少本人平時經常使用,有點像是三目運算子的感覺。

var a: Int?
let b = a ?? 0

如上程式碼,大致的意思就是假設a有值,即a不為nil的時候會把a賦值給b,如果a為nil則把0賦值給b。

  • 區間運算子[...]

這個操作符在遍歷集合等場景使用較多。

let names = ["1","2","3","4","5"]
for name in names[...3] {
    print(name)
}

沒錯,就是你心裡想的那樣,遍歷第0-3個元素,也可以加入<操作符,如[..<3]表示遍歷第0,1,2個元素。


Strings and Characters

這一小節主要是講解了Swift中的字串,有幾個知識點在上一篇文章Swift之旅_Welcome to Swift有提到過,主要是一個字串可以用”””來表示多行,還有新增了一個Substring型別,具體的可以參考上一篇文章。


Collection Types

這一小節講解的是Swift中的集合型別,主要是Array,Dictionary,Set。都比較簡單,而且Swift中用起來很方便。但是因為Set平時用的很少,我就著重看了一下。

A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equally, such that if a == b, it follows that a.hashValue == b.hashValue.

Set是一個無序不重複的集合,Set中的元素必須是可雜湊的。直接一直不知道雜湊是什麼鬼。最近一次學習的時候知道了雜湊其實就是一個單向雜湊函式。單項雜湊函式可以將一串資料計算得到一個獨一無二的值,所以也不難理解為啥Set中的元素必須是可雜湊的了,因為Set是不重複的。


3559363-4a56282a3c24a39c.png
Set.png

Set集合中一些常用的操作和對應的效果,官方文件中的這幅圖非常形象。


Control Flow

控制流,講解了一些迴圈和控制語句。

  • for迴圈

常見的都很簡單,不過文件中倒是提到了一種比較特別的迴圈方式,可以以一個數的倍數進行迴圈:

let minutes = 60
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    // render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}

//以下寫法可以到達hours,相當於小於等於吧
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
    // render the tick mark every 3 hours (3, 6, 9, 12)
}

此外我們都知道Swift中的switch語句是不用手動寫break的,Swift也提供了一個修飾符可以讓switch像c一樣, fallthrough,這個修飾符可以讓swift的switch語句匹配到對應的值之後繼續向下落。

let a = 5
switch a {
    case 5,6,7,8,9:
        print("case 1")
        fallthrough
    case 1,2,3,4,5:
        print("case 2")
        fallthrough
    default:
        print("default")
}

Functions

這個小節就比較重要了,講解的是Swift中的函式。

  • Variadic Parameters-可變引數

可變引數在絕對大多數開發語言中都存在,Swift也不列外。Swift中使用可變引數也是非常簡單。

func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
  • In-Out Parameters

在函式內部是無法直接更改引數的值的,或者這樣說比較貼切,引數在函式內部是let形式的。若想要達到更改呼叫函式時傳入的引數就需要用到inout這個修飾符。

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Closures

block的作用和oc的大致相同,但是這裡有多個注意點。

  • $0

Swift中的block可以直接用$0,$1...表示第1,2…引數,這樣可以直接不用寫明引數 和 in,這樣寫起來程式碼似乎是清爽了很多。

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: { $0 > $1 } )
  • 可以直接將函式賦值給block

只要引數和返回值都相同,就可以直接將函式賦值給block

var block: (()->Int) = test
func test() -> Int {
    return 0
}
  • Escaping Closures

逃逸閉包,相信很多同學都碰到過Xcode自動幫你在函式引數中的block前面加上@escaping修飾符。

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

當閉包作為函式引數傳遞,但是是在函式返回後呼叫時,閉包被稱為逃逸閉包。當你宣告一個有閉包引數的函式時,你可以在引數前面寫上@escaping表明閉包時允許逃逸的。

One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later.For example:

閉包可以逃避的一種方法是儲存在函式之外定義的變數中。例如,啟動非同步操作的許多函式都使用閉包引數作為完成回撥。函式在啟動操作後返回,但是在操作完成之前不會呼叫閉包-為了可以延遲呼叫,閉包需要時可逃逸的。例如:

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with @escaping, you would get a compile-time error.

someFunctionWithEscapingClosure函式有一個閉包引數並且把它新增到了函式外部的一個陣列中。如果你不在函式引數前面加上@ escaping,你會在編譯的時候得到一個error。

其實大概的意思就是如果這個block是作為函式引數使用,並且是在函式執行完畢之後呼叫的,就需要在函式的block引數前面加上@escaping修飾符。其實這個大多時候XCode幫我們做了。大家瞭解一下就行。

  • @autoclosure

這個原文有點難翻譯= =,直接上一段程式碼吧。

func test3(tBlock: @autoclosure ()->String) {
    print(tBlock())
}
test3(tBlock: "World")

大概意思就是和程式碼一樣吧,感覺就是加上@autoclosure之後,呼叫函式的時候可以直接傳入和閉包返回值相同型別的引數。


相關文章