本文系閱讀閱讀原章節後總結概括得出。由於需要我進行一定的概括提煉,如有不當之處歡迎讀者斧正。如果你對內容有任何疑問,歡迎共同交流討論。
如果你覺得這兩節的內容比較雜亂,強烈推薦我的這篇總結: 你其實真的不懂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
複製程式碼