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

242 阅读3分钟

本文系阅读阅读原章节后总结概括得出。由于需要我进行一定的概括提炼,如有不当之处欢迎读者斧正。如果你对内容有任何疑问,欢迎共同交流讨论。

如果你觉得这两节的内容比较杂乱,强烈推荐我的这篇总结: 你其实真的不懂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