文章目录
  1. 1. 原文代码
  2. 2. 代码段说明
  3. 3. 其他

原文地址:Functional Snippet #2: Function Composition

原文代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func getContents(url: String) -> String {
return NSString(contentsOfURL: NSURL(string: url),
encoding: NSUTF8StringEncoding, error: nil)
}
func lines(input: String) -> [String] {
return input.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet())
}
let linesInURL = { url in countElements(lines(getContents(url))) }
linesInURL("http://www.objc.io")
//运算符重载,通过实现函数组合
infix operator >>> { associativity left }
func >>> <A, B, C>(f: B -> C, g: A -> B) -> A -> C {
return { x in f(g(x)) }
}
let linesInURL2 = countElements >>> lines >>> getContents
linesInURL2("http://www.objc.io/books")

代码段说明

  • 代码实现的功能是:给定一个URL,获取内容,按照分行符分割内容,得到内容分割后的数组,然后计算数组的大小。一共有三个函数需要依次调用。
  • 前半部分通过传统的函数逐次调用实现功能,最后通过一个闭包调用完成功能。
  • 后半部分通过运算符重载,传入2个闭包参数,返回一个闭包。最后的调用定义通过运算符连接完成
  • 但是,以上代码在Xcode6.4(Swift1.2)下会报错,修改为以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import Foundation
func getContents(url: String) -> String {
return NSString(contentsOfURL: NSURL(string: url)!,
encoding: NSUTF8StringEncoding, error: nil)! as String
}
func lines(input: String) -> [String] {
return input.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet())
}
let linesInURL = { url in count(lines(getContents(url))) }
linesInURL("http://codebuild.me")
infix operator >>> { associativity left }
func >>> <A, B, C>(f: B -> C, g: A -> B) -> A -> C {
return { x in f(g(x)) }
}
let linesInURL2 = count >>> lines >>> getContents
linesInURL2("http://codebuild.me")
//it doesn't matter whether the associativity is left or right, both are correct..
//i think '<<<' should be easily understood over '>>>'.., My reason is, excuting the methods should begin from right to left,function getContents excuted firstly, "lines" seconedly, the end is "count"
infix operator <<< { associativity left }
func <<< <A, B, C>(f: B -> C, g: A -> B) -> A -> C {
return { x in f(g(x)) }
}
let linesInURL3 = (count <<< lines) <<< getContents
linesInURL3("http://codebuild.me")

主要变化是:

  • NSURL的的便利构造器定义为可选返回,而NSString构造器必须传入确定的NSURL值,只能对构造器的返回进行拆包,否则会报错。
  • NSStringStringSwift1.2中不能进行隐式转换。函数getContents中使用as把拆包后的NSString强制转换成String
  • 函数countElement改成count,用来计算数组的个数.

其他

本段代码get到新技能,如何自定义运算符。喵神的书已经对此进行了详细解释,这里就不多介绍。
这里主要讲一下2个细节的地方:

  • associativity无论是left结合,还是right结合。都能够正确的输出。并且即使是加括号显式指定优先级,结果也正常。猜测可能是跟函数的闭包参数传递有关,因为闭包的传递依赖,所以一定是从最右边开始执行。大家看看有没有更合理的解释,希望能留言指导。。
  • 另外我觉得<<<>>>更能表达从右边开始执行的顺序。

参考资料:

文章目录
  1. 1. 原文代码
  2. 2. 代码段说明
  3. 3. 其他