第七章——字串(字元流)

bestswifter發表於2017-12-27

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

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

如果型別比較複雜,你可能需要考慮實現Streamable協議。在這個協議中定義了一個範型函式writeTo,引數所屬的型別必須實現OutputStreamType協議,方法的呼叫者把自己寫入這個引數中(最簡單方法就是呼叫print函式)。我們呼叫的是過載了的print函式,所以千萬不要忘記加上引數toStream,否則會很難發現這個錯誤。舉個例子說明:

extension Person: Streamable {
func writeTo<Target : OutputStreamType>(inout target: Target) {
print("[", terminator: "", toStream: &target)
print("Name is \(name)", terminator: "", toStream: &target)
print(", Age is \(age)", terminator: "", toStream: &target)
print("]", terminator: "", toStream: &target)
}
}
複製程式碼

因為字串就實現了OutputStreamType協議,所以我們可以把Person型別的變數寫入到字串中:

var description = ""
let person = Person(name: "kt", age: 21)
person.writeTo(&description)

print(description)	// 輸出結果:[Name is kt, Age is 21]
複製程式碼

我們把實現了OutputStreamType協議的型別稱為輸出流,String是標準庫中定義的唯一一個輸出流型別。當然,也可以手動定義自己的輸出流,只要實現OutputStreamType協議中定義的write方法即可:

struct ArrayStream: OutputStreamType {
var buf: [String] = []
mutating func write(string: String) {
buf.append(string)
}
}
複製程式碼

這樣,我們就可以把多個字串寫入ArrayStream型別中:

var arrayStream = ArrayStream()
let s1 = "s1"
let s2 = "s2"
s1.writeTo(&arrayStream)
s2.writeTo(&arrayStream)
print(arrayStream)	// 如果你需要定製輸出效果,可以像上一節所說的,實現CustomStringConvertible協議
複製程式碼

需要強調一點,這並非輸出流的正確使用方法,它僅用於演示OutputStreamType的工作原理。

雖然字串是唯一實現了OutputStreamableType協議的型別,但諸如print這樣的函式,也可以很好地處理Streamable型別的引數,舉個例子:

struct SlowStreamer: Streamable, ArrayLiteralConvertible {
let contents: [String]
init(arrayLiteral elements: String...) {
contents = elements
}

func writeTo<Target : OutputStreamType>(inout target: Target) {
for x in contents {
print(x, toStream: &target)
sleep(1)
}
}
}

let slow: SlowStreamer = [
"You'll see that ghis gets",
"written slowly line-by-line",
"to the standard output"
]

print(slow)
複製程式碼

執行程式後你會發現,在執行print函式的過程中,每一行字串不斷地被輸出。在writeTo函式的內部我們呼叫了print方法,其第二個引數為標準輸出,你也可以實現和此類似的標準錯誤輸出:

struct StdErr: OutputStreamType {
mutating func write(string: String) {
fputs(string, stderr)
}
}

var standarderror = StdErr()
print("oops!", toStream: &standarderror)    // 輸出結果:oops!
複製程式碼

還可以在輸出流中對輸入值做些處理,我們實現一個自定義的輸出流:

struct ReplacingStream<T: OutputStreamType>: OutputStreamType {
var outputStream: T
let toReplace: DictionaryLiteral<String, String>
init(replacing: DictionaryLiteral<String, String>, output: T) {
outputStream = output
toReplace = replacing
}

mutating func write(string: String) {
let toWrite = toReplace.reduce(string) {
$0.stringByReplacingOccurrencesOfString($1.0, withString: $1.1)
}
print(toWrite, separator:"", toStream: &outputStream)
}
}
複製程式碼

如果把字串輸出到這個流而不是標準輸出流,我們就達到了處理字串的效果:

var replacer = ReplacingStream(replacing: ["1":"2"], output: standarderror)
let source = "111333"
print(source, toStream: &replacer)	// 輸出結果:222333
複製程式碼

相關文章