Swift-函数式编程(Funtional Programming)

117 阅读1分钟
  • 函数式编程(Funtional Programming,简称FP),是一种编程范式,也就是如何编写程序的方法论
  1. 主要思想:把计算过程尽量分解成一系列可服用函数的的调用
  2. 主要特征:函数是“第一等公民”
  • 函数与其他数据类型一样的地位,可以赋值给其他变量,也可以作为函数参数,函数返回值

函数合成

假设要实现以下功能:[(num + 3) *5 - 1] % 10 /2

let num = 1
func add(_ v:Int) ->(Int) ->Int {{$0 + v}}
func sub(_ v:Int) ->(Int) ->Int {{$0 - v}}
func multiple(_ v:Int) ->(Int) ->Int {{$0 * v}}
func divide(_ v:Int) ->(Int) ->Int {{$0 / v}}
func mod(_ v:Int) ->(Int) ->Int {{$0 % v}}

infix operator >>> : AdditionPrecedence
func >>><A,B,C>(_ f1:@escaping (A) -> B,
                _ f2;@escaping (B) -> C) -> (A) ->C {{f2(f1($0))}}

var fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
fn(num)

高阶函数(Higher-Order Function) 高阶函数是至少满足下列一个条件的函数: 接受一个或多个函数作为输入(map、filter、reduce等) 返回一个函数

柯里化(Curring) 什么是柯里化? 将一个接受多参数的函数变换为一系列只接收单个参数的函数

func add(_ v1:Int,_ v2:Int) -> Int {v1 + v2}
add(10,20)
func add(_v:Int) ->(Int) -> Int{{$0 + v}}
add(10)(20)

Array,Optional的map方法接收的参数就是一个柯里化函数

func add2(_ v1:Int,_ v2: Int,_ v3:Int) -> Int{v1 + v2 + v3}
func add2(_ v3:Int) -> (Int) ->(Int) -> Int {
    // v2 == 20
    return { v2 in
            // v1 == 10
            return { v1 in
                return v1 + v2 + v3
            }
    }
}
add2(30)(20)(10)
func add(_ v1:Int,_ v2:Int) -> Int {v1 + v2}
func sub(_ v1:Int,_ v2:Int) -> Int {v1 - v2}
func multiple(_ v1:Int,_ v2:Int) -> Int {v1 * v2}
func divide(_ v1:Int,_ v2:Int) -> Int {v1 / v2}
func mod(_ v1:Int,_ v2:Int) -> Int {v1 % v2}

func currying<A,B,C>(_ fn:@escaping (A,B) ->C) ->(B) -> (A) -> C {
    return { b in
        return { a in
            return fn(a,b)
        }   
    }
}
print(currying(add)(20)(100)) 
print(currying(sub)(20)(100))
print(currying(multiple)(20)(100))
print(currying(divide)(20)(100))
print(currying(mod)(20)(100))

prefix func ~<A,B,C>(_ fn:@escaping (A,B) ->C) ->(B) ->(A) -> C {
    {b in {a in fn(a.b)}}
}
print((~sub)(20)(10))

面向协议编程

面向协议编程(Protocol Oriented Programming,简称POP),是Swift的一种编程范式 同时,Swift也是一门面向对象的编程语言(Object Oriented Programming,简称OOP),在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方。 OOP 的三大特性:封装、继承、多态

POP的解决方案

protocol Runnable {
    func run()
}
extension Runnable {
    fun run(){
        print("run")
    }
}
class BVC:UIViewController,Runnable {}
class DV:UITableViewController,Runnable {}

POP 的注意点

优先考虑创建协议,而不是父类(基类) 优先考虑值类型(struct、enum)、而不是引用类型(class) 巧用协议的扩展功能 不要为了面向协议而使用协议。

利用协议实现前缀效果

// 前缀类型
struct JG<Base> {
    var base:Base
    init(_ base:Base){
        self.base = base
    }
}
// 利用协议扩展前缀属性
protocol JGCompatible {}
protocol JGCompatible{
    var jg:JG<Self> {JG(self)}
    static var jg:MJ<Self>.Type {MJ<Self>.self}
}
// 给字符串扩展功能
// 让String 拥有jg前缀属性
extension String : JGCompatible{}

class Person {}
extension Person : JGCompatible{}

struct Dog {}
extension Dog : JGCompatible{}

// 给String.jg 、String().jg前缀扩展功能
//extension JG where Base == String {
//    var numberCount:Int {
//        var count = 0
//        for c in base where ("0"..."9").contains(c) {
//            count += 1
//        }
//        return count
//    }
//    static func test (){
        
//    }
//}
// String,NSString 都遵守ExpressibleByStringLiteral,只要遵守这个协议的都可以使用
extension JG where Base :ExpressibleByStringLiteral {
    var numberCount:Int {
        var count = 0
        for c in base as! String where ("0"..."9").contains(c) {
            count += 1
        }
        return count
    }
    static func test (){
        
    }
}

// : 代表Person及Person子类都拥有这个方法
extension JG where Base:Person {
    func run() {
        print("run")
    }
}

print("123kkkk".jg.numberCount) 
var person = Person()
person.jg.run()
String.jg.test()

利用协议实现类型判断

func isArray(_ value:Any) -> Bool {value is [Any]}
isArray([1,2])
isArray(["1",2])
isArray(NSArray)
isArray(NSMutableArray())

protocol ArrayType {}
extension Array:ArrayType {}
extension NSArray:ArrayType {}

func isArrayType(_ type:Any.Type) -> Bool {
    //type is [Any].Type
    type is ArrayType.Type
}
isArrayType([Int].self)
isArrayType([Any].self)
isArrayType(NSArray.self)
isArrayType(NSMutableArray.self)

响应式编程

  • 响应式编程(Reactive Programming,简称RP),一种编程范式,可以简化异步编程,提供更优雅的数据绑定
  • 一般与函数式融合在一起,所以也会叫做:函数响应式编程(Functional Reactive Programming,简称FRP)

RxSwift的核心角色

  • Observable:负责发送事件(Event)
  • Observer:负责订阅Observable,监听Observable发送的事件(Event)

事件(Event)有3种

public enum Event<Element> {
    case next(Element)// 携带具体数据
    case error(Swift.Error) // 携带错误信息,表明Observable终止,不会再发出事件
    case completed //表明Observable终止,不会再发出事件
}

创建、订阅Observable1

var observable = Observable<Int>.create { observer in
    observer.onNext(1)
    observer.onCompleted()
    return Disposablees.create()
}
// 等价于
observable = Observable.just(1)
observable = Observable.of(1)
observable = Observable.from([1])

Disposable 每当Observable被订阅时,都会返回一个Disposable实例,当调用Disposable的dispose,就相当于取消订阅 在不需要再接收事件时,建议取消订阅,释放资源。有三种常见方式取消订阅

// 立即取消订阅(一次性订阅)
observable.subscribe{event in print(event)}.dispose()

// 当bag销毁(deinit)时,会自动调用Disposable实例的dispose
let bag = DisposeBag()// 控制器销毁了,就销毁啦
observable.subscribe{event in print(event)}.dispose(by:bag)

// self销毁时(deinit)时,会自动调用Disposable实例的dispose
let _ = observable.takeUntil(self.rx.deallocated).subscribe{
    event in print(event)
}

创建Observer

let observer = AnyObserver<Int>.init{ event in 
    switch event {
        case .next(let data):print(data)
        case .completed:print("completed")
        case .error(let error):print("error",error)
    }
}
observable.just(1).subscribe(observer).dispose()
let binder = Binder<String>(label){label,text in label.text = text}
Observable.just(1).map{"数值是\($0)"}.subscribe(binder).dispose()
Observable.just(1).map{"数值是\($0)"}.bind(to:binder).dispose()

传统的状态监听 在开发中经常要对各种状态进行监听,传统的常见监听方案有

Rxswift

button.rx.tap.subscribe(onNext:{
    print("按钮被点击了1")
}).disposed(by:bag)
let data = Observable.just([Person(name:"Jack",age:10),Person(name:"Rose",age:20)])
data.bind(to:tableView.rx.items(cellIdentifier:"cell")){
    row,person,cell in 
    cell.textLabel?text = person.name
    cell.detailTextLabel?.text = "\(person.age)"
}
tableView.rx.modelSelected(Person.self).subscribe(
    onNext:{ person in print("点击了",person.name)}).disposed(by:bag)

状态监听2

class Dog:NSObject {
    @objc dynamic var name:String?
}
dog.rx.observe(String.self,"name")
.subscribe(onNext:{name in print("name is",name ?? "nil")})
.disposed(by:bag)
dog.name = "larry"
dog.name ="wangwang"

通知监听

NotificationCenter.default.rx
.notification(UIApplication.didEnterBackgroundNotification)
.subscribe(onNext:{notification in print("APP 进入后台",notification)})
.disposed(by:bag)

即是Observale,又是Observer

Observeable.just(0.8).bind(to:slider.rx.value).disposed(by:bag)
slider.rx.value.map {
    "当前数值是:\($0)"
}.bind(to:textField.rx.text).disposed(by:bag)

textField.rx.text.subscript(onNext:{text in print("text is",text ?? "nil")}).disposed(by:bag)