第七章——字串(字串除錯)

bestswifter發表於2017-12-27

本文系閱讀閱讀原章節後總結概括得出。由於需要我進行一定的概括提煉,如有不當之處歡迎讀者斧正。如果你對內容有任何疑問,歡迎共同交流討論。

如果你覺得這兩節的內容比較雜亂,強烈推薦我的這篇總結: 你其實真的不懂print("Hello,world")

不知道你有沒有注意到一個細節,不管你使用什麼型別的引數,printString.init()函式總是可以正常工作。比如我們定義一個結構體,其中年齡作為私有屬性需要對外保密:

struct Person {
var name: String
private var age: Int

init(name: String, age: Int) {
self.name = name
self.age = age
}
}
複製程式碼

分別使用printString.init()函式,檢視結果:

let kt = Person(name: "kt", age: 21)
let s: String = String(kt)
print(kt)	// 輸出結果:Person(name: "kt", age: 21)
print(s)	// 輸出結果:Person(name: "kt", age: 21)
複製程式碼

好訊息是這兩個函式執行正常,列印出了結構體的所有資訊,但缺點是私有屬性也被顯示出來了。如果想自定義輸出格式,或避免暴露私有成員,也很容易實現,只需要實現CustomStringConvertible協議即可:

extension Person: CustomStringConvertible {
var description: String {
return "Name is \(name)"
}
}
複製程式碼

這樣我們就可以完全自定義輸出結果。呼叫printString.init()函式將會得到Name is kt。如果你有過Java程式設計的經驗,你會發現這和toString函式有異曲同工之妙。

如果只是專門用於除錯,你還可以實現CustomDebugStringConvertible協議:

extension Person: CustomStringConvertible, CustomDebugStringConvertible {
var debugDescription: String {
return "In debugging: name is \(name)"
}
}
複製程式碼

為了使用這個協議,你可以呼叫String.init(reflecting: T)方法,這個方法得到的字串是T型別在實現CustomDebugStringConvertible協議時定義的計算屬性debugDescription。舉個例子說明:

let debug = String(reflecting: kt)
print(debug)	// 輸出結果:In debugging: name is kt
複製程式碼

或者你也可以直接呼叫debugPrint函式:

debugPrint(kt)	// 輸出結果:In debugging: name is kt
複製程式碼

需要說明的是,即使你沒有實現CustomDebugStringConvertible協議,也依然可以使用debugPrintString.init(reflecting: T)方法,此時的字串會是CustomStringConvertible協議中的計算屬性description

由於實現了CustomStringConvertible協議的型別一般都有很好的輸出結果,你或許會實現這樣的程式碼:

func doSomethingAttractive<T: CustomStringConvertible>(with value: T) {
// 可能會呼叫print方法輸出value
}
複製程式碼

如果你這麼做了,很快你會發現String型別並沒有實現CustomStringConvertible協議,而字串恰好是最常被輸出的型別。這是因為Swift不希望我們以這種方式使用CustomStringConvertible協議。我們不應該去檢查一個型別是否具有description屬性,而是應該不管在什麼情況下都使用String.init。我們也應該認識到,如果一個型別並不是可輸出的,呼叫print方法確實會得到一個很醜的結果。因此,除非是一個非常簡單的類,我們總是應該實現CustomStringConvertible協議,這用不了太多時間,但是會在以後的除錯過程中起到很大的作用,正所謂磨刀不誤砍柴工!

相關文章