函數(shù)式編程(FP)
/// 把接受兩個(gè)參數(shù)的函數(shù), 變?yōu)榻邮芤粋€(gè)參數(shù)
let num = 1
func add(_ v: Int) -> (Int) -> Int{
reutrn {
$0 + v
}
}
let fn = add(3)
fn(num)
//簡(jiǎn)寫(xiě): add(3)(num) //函數(shù)式編程的特征, 先接受一個(gè)參數(shù), 再接受一個(gè)參數(shù)
print(fn(5), fn(100), fn(1000))
/// 函數(shù)合成
let fn1 = add(3)
let fn2 = multiple(5)
let fn3 = sub(1)
let fn4 = mod(10)
let fn5 = divide(2)
// 假設(shè)要實(shí)現(xiàn)以下功能: [(num + 3) * 5 - 1] % 10 / 2
//print(fn5(fn4(fn3(fn2(fn1(num))))))
func composite(_ f1: @escaping (Int) -> Int, f2: @escaping (Int) -> Int) -> (Int) -> Int{
return {
f2(f1($0))
}
}
let fn = composite(add(3), multiple(5))
print(fn(num))//20
//對(duì)上面??優(yōu)化:
infix operator >>> : AdditionPrecedence //定義>>> 使它跟加法差不多
/*
func >>>(_ f1: @escaping (Int) -> Int, f2: @escaping (Int) -> Int) -> (Int) -> Int{
return {
f2(f1($0))
}
}
*/
func >>><A, B, C>(_ f1: @escaping (A) -> B, f2: @escaping (B) -> C) -> (A) -> C {
return {
f2(f1($0))
}
}
let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
print(fn(num))//20
一、函數(shù)式編程(FP)-高階函數(shù)
高階函數(shù)至少滿足下面的一個(gè)條件的函數(shù):
接受一個(gè)或多個(gè)函數(shù)作為輸入(map晾咪、filter收擦、reduce等)
返回一個(gè)函數(shù)
二、函數(shù)式編程(FP) - 柯里化(Currying)
什么是柯里化? 將一個(gè)接受多參數(shù)的函數(shù)變換為一系列只接受單個(gè)參數(shù)的函數(shù).
Array谍倦、Optional的map函數(shù)就是柯里化函數(shù).
給定任何一個(gè)函數(shù)都能柯里化, 比如下面??
func add1(_ v1: Int, _ v2: Int) -> Int {v1 + v2}
add1(10, 20)
//柯里化后的效果: add3(20)(10)
func add3(_ v: Int) -> (Int) -> Int { { $0 + v } }
func add2(_ v1: Int, _ v2: Int, _ v3: Int) -> Int { v1 + v2 + v3 }
add2(10, 20, 30)
//柯里化后的效果: add4(30)(20)(10)
func add4(_ v3: Int) -> (Int) -> (Int) -> Int {
return { v2 in //v2 == 20
return { v1 in // v1 == 10
return v1 + v2 + v3
}
}
}
/// 柯里化最終版本: 傳一個(gè)兩個(gè)參數(shù)的函數(shù)過(guò)來(lái), 自動(dòng)柯里化
func currying<A, B, C>(_ fn: @escaping (A, B) -> C) -> (B) ->(A) -> C{
return { b in
return { a in
return fn(a, b)
}
}
}
curring(add1)(20)(10)//使用效果
//對(duì)上面??簡(jiǎn)化:
prefix func ~<A, B, C>(_ fn: @escaping(A, B)-> C) ->(B) ->(A) -> C {
{b in { a in fn(a, b) } }
}
print((~sub)(20)(10))
infix operator >>> : AdditionPrecedence
func >>> <A, B, C>(_ f1: @escaping (A) -> B,
_ f2: @escaping(B) -> C)
-> (A) -> C { { f2(f1($0)) } }
let fn = (~add)(3) >>> (~multiple)(5) >>> (~sub)(1) >>> (~mod)(10) >>> (~divide)(2)
print(fn(1))
/// 柯里化最終版本: 傳一個(gè)三個(gè)參數(shù)的函數(shù)過(guò)來(lái), 實(shí)現(xiàn)自動(dòng)柯里化
prefix func ~<A, B, C, D>(_ fn: @escaping(A, B, C)-> D) ->(C) ->(B) ->(A) -> D {
{c in {b in { a in fn(a, b, c) } } }
}
print((~add2)(30)(20)(10))
三塞赂、函數(shù)式編程-函子(Functor)
像Array、Optional這樣支持map運(yùn)算的類(lèi)型, 稱(chēng)為函子(Functor).
// Array<Element>
public func map<T>(_ transform: (Element) ->T) -> Array<T>
// Optional<Wrapped>
public func map<U>(_ transform: (Wrapped) -> U) -> Optional<U>
//怎么樣的Type才能稱(chēng)為函子(Functor)?
func map<T>(_ fn: (Inner) -> T) > Type<T>//支持這個(gè)運(yùn)算格式的就是函子
適用函子
四昼蛀、函數(shù)式編程-適用函子(Applicative Functor)
對(duì)任意一個(gè)函子F, 如果能支持一下運(yùn)算, 該函子就是一個(gè)適用函子
func pure<A>(_ value: A) -> F<A>
func <*><A, B>(fn: F<(A)->B>, value: F<A>) -> F<B>
五宴猾、函數(shù)式編程-單子(Monad)
對(duì)任意一個(gè)類(lèi)型F, 如果能支持一下運(yùn)算, 那么就可以稱(chēng)為是一個(gè)單子(Monad)
func pure<A>(_ value: A) -> F<A>
func flatMap<A, B>(_ value: F<A>, _ fn:(A) -> F<B>) ->F<B>
很顯然Array和Optional是單子
面向協(xié)議編程(POP)
面向協(xié)議編程(Protocol Oriented Programming, 簡(jiǎn)稱(chēng)POP)
是Swift的一種編程范式, Apple于2015年WWDC提出
在Swift的標(biāo)準(zhǔn)庫(kù)中, 能見(jiàn)到大量POP的影子
同時(shí), Swift也是一門(mén)面向?qū)ο蟮木幊陶Z(yǔ)言(Object Oriented Programming, 簡(jiǎn)稱(chēng)OOP)
在Swift開(kāi)發(fā)中, OOP和POP相輔相成的
OOP的三大特性: 封裝圆存、繼承、多態(tài)
繼承的經(jīng)典使用場(chǎng)景:
當(dāng)多個(gè)類(lèi)(比如A仇哆、B沦辙、C類(lèi))具有很多共性時(shí), 可以將這些共性抽取到一個(gè)父類(lèi)中(比如D類(lèi)),最后A、B讹剔、C都繼承D類(lèi)
OOP的不足:
比如??如何將BVC油讯、DVC的公共方法run抽取出來(lái)?
class BVC: UIViewController {
func run() {
print("run")
}
}
class DVC: UITableViewController {
func run() {
print("run")
}
}
//基于OOP想到的一些解決方案??
1.將run方法放到另一個(gè)對(duì)象A中, 然后BVC、DVC擁有對(duì)象A屬性
??多了一些額外的一類(lèi)關(guān)系
2.將run方法增加到UIViewController分類(lèi)中
??UIVIewController會(huì)越來(lái)越臃腫, 而且會(huì)影響它的其他所有子類(lèi)
3.將run方法抽取到新的父類(lèi), 采用多繼承? (C++支持多繼承)
??會(huì)增加程序設(shè)計(jì)的復(fù)雜度, 產(chǎn)生菱形繼承等問(wèn)題, 需要開(kāi)發(fā)者額外解決
//POP的解決方案:?
protocol Runnable {
func run()
}
extension Runnable { //Swift支持?jǐn)U展協(xié)議的具體實(shí)現(xiàn)(類(lèi)似Java的接口)
func run() {
print("run")
}
}
class BVC: UIViewController, RunNable {}
class DVC: UITableViewController, Runnable {}
//POP的注意點(diǎn)
優(yōu)先考慮創(chuàng)建協(xié)議, 而不是父類(lèi)(基類(lèi))
優(yōu)先考慮值類(lèi)型( struct延欠、enum), 而不是引用類(lèi)型(class)
巧用協(xié)議的擴(kuò)展功能
不要為了面向協(xié)議而使用協(xié)議
一陌兑、給類(lèi)拓展功能
var str = "123rrr"
/// 需求: 查找字符串中有幾個(gè)數(shù)字
//方法一: 通過(guò)擴(kuò)展
extension String{
var mj_numberCount: Int {//計(jì)算屬性
var count = 0
for c in self where ("0"..."9").contains(c){
count += 1
}
return count
}
}
print(str.mj_numberCount)
/// 對(duì)上面??進(jìn)行優(yōu)化升級(jí), 效果: print(str.mj.numberCount)
var str = "123rrr"
struct MJ {
var string: String
init(_ string: String){//持有外部傳入的參數(shù)
self.string = string
}
var numberCount: Int {//擴(kuò)展功能方法
var count = 0
for c in string where ("0"..."9").contains(c){
count += 1
}
return count
}
}
extension String{
var mj: MJ { return MJ(self) }
}
print("123ooo999".mj.numberCount)
/// 對(duì)上面??進(jìn)行優(yōu)化升級(jí), 不能只支持String類(lèi)型, 讓它更通用
struct MJ<Base> {//使用泛型增加通用性
var base: Base
init(_ base: Base){//持有外部傳入的參數(shù)
self.base = base
}
}
extension String{
var mj: MJ<String> { return MJ(self) }
}
class Person {}
extension Person{
var mj: MJ<Person> { return MJ(self) }
}
//擴(kuò)展的是對(duì)象方法
extension MJ where Base == String { //此處是計(jì)算屬性, 本質(zhì)是一個(gè)方法
var numberCount: Int {//擴(kuò)展功能方法
var count = 0
for c in base where ("0"..."9").contains(c){
count += 1
}
return count
}
}
extension MJ where Base: Person {
func run() {//擴(kuò)展功能方法
print("跑起來(lái)了")
}
}
print("12kkk999".mj.numberCount)
Person().mj.run()
/// 對(duì)上面??進(jìn)行優(yōu)化升級(jí), 支持拓展類(lèi)方法. 效果String.mj.test()
//sp1.前綴類(lèi)型
struct MJ<Base> {//使用泛型增加通用性
var base: Base
init(_ base: Base){//持有外部傳入的參數(shù)
self.base = base
}
}
//sp2.讓想擴(kuò)充方法的類(lèi)型, 擴(kuò)充前綴屬性
extension String{
var mj: MJ<String> { MJ(self) }//返回實(shí)例屬性
static var mj: MJ<String>.Type { return MJ<String>.self } // static屬性用類(lèi)是可以訪問(wèn)出來(lái)的, 返回類(lèi)型屬性
//注意: xx類(lèi).self 的類(lèi)型是 xx類(lèi).Type. 比如上面 MJ.self 的類(lèi)型是 MJ.Type
}
//sp3.給前綴擴(kuò)展方法
extension MJ where Base == String {
var numberCount: Int {//擴(kuò)展實(shí)例方法
var count = 0
for c in base where ("0"..."9").contains(c){
count += 1
}
return count
}
static func test(){//擴(kuò)展類(lèi)方法
print("執(zhí)行了類(lèi)方法")
}
}
String.mj.test()
/// 對(duì)上面??sp2進(jìn)行優(yōu)化升級(jí), 利用協(xié)議protocol擴(kuò)展前綴屬性
//sp1.前綴類(lèi)型
struct MJ<Base> {//使用泛型增加通用性
var base: Base
init(_ base: Base){//持有外部傳入的參數(shù)
self.base = base
}
}
//sp2.利用協(xié)議protocol擴(kuò)展前綴屬性
protocol MJCompatible {} //協(xié)議里面只能聲明一些東西,想給協(xié)議擴(kuò)展一些東西的話要用extension
extension MJCompatible{//擴(kuò)展協(xié)議
var mj: MJ<Self> { MJ(self) }//返回實(shí)例屬性
static var mj: MJ<Self>.Type { MJ<Self>.self } // static屬性用類(lèi)是可以訪問(wèn)出來(lái)的, 返回類(lèi)型屬性
//注意: xx類(lèi).self 的類(lèi)型是 xx類(lèi).Type. 比如上面 MJ.self 的類(lèi)型是 MJ.Type
}
//以后誰(shuí)想給前綴擴(kuò)展這個(gè)功能, 就讓讓它遵守這個(gè)協(xié)議
extension String: MJCompatible{} //讓String擁有mj前綴屬性
//sp3.給String.mj、String().mj前綴擴(kuò)展功能
extension MJ where Base == String {
var numberCount: Int {//擴(kuò)展實(shí)例方法
var count = 0
for c in base where ("0"..."9").contains(c){
count += 1
}
return count
}
static func test(){//擴(kuò)展類(lèi)方法
print("執(zhí)行了類(lèi)方法")
}
}
String.mj.test()
/// 對(duì)上面??進(jìn)行優(yōu)化升級(jí), 支持?jǐn)U展mutating功能 ?
//sp1.前綴類(lèi)型
struct MJ<Base> {//使用泛型增加通用性
var base: Base
init(_ base: Base){//持有外部傳入的參數(shù)
self.base = base
}
}
//sp2.利用協(xié)議protocol擴(kuò)展前綴屬性
protocol MJCompatible {} //協(xié)議里面只能聲明一些東西,想給協(xié)議擴(kuò)展一些東西的話要用extension
extension MJCompatible{//擴(kuò)展協(xié)議
var mj: MJ<Self> {//不要返回只讀的計(jì)算屬性, 為了以后擴(kuò)展mutating, 換成普通計(jì)算屬性
set {} //為了mutating語(yǔ)法能夠通過(guò)
get { MJ(self) }
}
static var mj: MJ<Self>.Type {
set {}
get { MJ<Self>.self }
} // static屬性用類(lèi)是可以訪問(wèn)出來(lái)的, 返回類(lèi)型屬性
//注意: xx類(lèi).self 的類(lèi)型是 xx類(lèi).Type. 比如上面 MJ.self 的類(lèi)型是 MJ.Type
}
extension String: MJCompatible{} //讓String遵守這個(gè)協(xié)議
//sp3.給String.mj由捎、String().mj前綴擴(kuò)展功能
extension MJ where Base == String {
var numberCount: Int {//擴(kuò)展實(shí)例方法
var count = 0
for c in base where ("0"..."9").contains(c){
count += 1
}
return count
}
mutating func run(){//mutating作用是讓MJ(結(jié)構(gòu)體)實(shí)例是可修改的
//切記常量是不可修改的, 不要用常量調(diào)用mutating方法
print("執(zhí)行了mutating方法")
}
static func test(){//擴(kuò)展類(lèi)方法
print("執(zhí)行了類(lèi)方法")
}
}
var str = "123321"
str.mj.run()
//注意: 父類(lèi)擴(kuò)展了功能, 子類(lèi)也會(huì)擁有這些功能.
二兔综、給NSString、String隅俘、NSMutableString同時(shí)擴(kuò)展方法
//NSString邻奠、String、NSMutableString共同點(diǎn): 因?yàn)樗鼈兌甲裱璄xpressibleByStringLiteral這個(gè)協(xié)議,才能用字符串字面量進(jìn)行初始化.
struct MJ<Base> {
var base: Base
init(_ base: Base){
self.base = base
}
}
protocol MJCompatible {}
extension MJCompatible{
var mj: MJ<Self> {
set {}
get { MJ(self) }
}
static var mj: MJ<Self>.Type {
set {}
get { MJ<Self>.self }
}
}
extension String: MJCompatible{}
extension NSString: MJCompatible{}//NSString遵守了和這個(gè)協(xié)議, 它的子類(lèi)NSMutableString也就遵守了這個(gè)協(xié)議
//代表我這個(gè)泛型遵守ExpressibleByStringLiteral這個(gè)協(xié)議的, 都可以用numberCount方法
extension MJ where Base: ExpressibleByStringLiteral {//Base:后面能放協(xié)議为居、結(jié)構(gòu)體碌宴、類(lèi)型、枚舉
var numberCount: Int {
// // 只要是能通過(guò)字符串字面量初始化的, 都是能轉(zhuǎn)成Swift的String的
// // 能夠通過(guò)字符串字面量初始化的只有NSString蒙畴、String贰镣、NSMutableString
// var string = base as! String
var count = 0
for c in (base as! String) where ("0"..."9").contains(c){
count += 1
}
return count
}
mutating func run(){//mutating作用是讓MJ(結(jié)構(gòu)體)實(shí)例是可修改的
//切記常量是不可修改的, 不要用常量調(diào)用mutating方法
print("執(zhí)行了mutating方法")
}
static func test(){//擴(kuò)展類(lèi)方法
print("執(zhí)行了類(lèi)方法")
}
}
var str1 = "123321"
var str2: NSString = "123xxx"
var str3: NSMutableString = "123xxx"
print(str1.mj.numberCount)
print(str2.mj.numberCount)
print(str3.mj.numberCount)
三、利用協(xié)議實(shí)現(xiàn)類(lèi)型判斷
需求1: 判斷傳入的實(shí)例對(duì)象是否為數(shù)組.
func isArray(_ value: Any)->Bool{
// return value is Array<Any>
return value is [Any] //對(duì)上面??的簡(jiǎn)寫(xiě): Any表示數(shù)組里可以裝入任何東西
}
print(isArray([1, 2]))
print(isArray(["1", 2]))
print(isArray(NSArray())) //OC的類(lèi)型都是能直接橋接Swift里對(duì)應(yīng)的類(lèi)型, 例如: NSArray() as Array
print(isArray(NSMutableArray()))
print(isArray("23123"))
需求2: 判斷傳入的類(lèi)型是否是數(shù)組類(lèi)型
// 一般判斷某個(gè)類(lèi)型是否是數(shù)組類(lèi)型,這么判斷:
let type = NSArray.self
print(type is NSArray.Type
//實(shí)例中, 判斷傳入的類(lèi)型是否是數(shù)組類(lèi)型
//sp1.定義一個(gè)協(xié)議,讓所有數(shù)組類(lèi)型都遵守這個(gè)協(xié)議
protocol ArrayType {}
extension Array: ArrayType{}
extension NSArray: ArrayType{}
//sp2.判斷類(lèi)型是否是協(xié)議的type
func isArrayType(_ type: Any.Type) ->Bool {
// type is [Any].Type//這樣寫(xiě)無(wú)法正確判斷出數(shù)組類(lèi)型, 因?yàn)閇Any].Type和[Int].type等不是一個(gè)東西
//解決方法: 使用協(xié)議來(lái)完成這個(gè)判斷
type is ArrayType.Type//協(xié)議最終就是一個(gè)具體類(lèi)型
}
//sp3.實(shí)戰(zhàn)中使用
print(isArrayType([Int].self))
print(isArrayType([Any].self))
print(isArrayType(NSArray.self))
print(isArrayType(NSMutableArray.self))
print(isArrayType(String.self))
//不管是枚舉膳凝、協(xié)議碑隆、類(lèi)、結(jié)構(gòu)體, 都有.Type
//定義ttt這個(gè)變量, 表示遵守ArrayType協(xié)議的類(lèi), 都可以寫(xiě)過(guò)來(lái)
var ttt: ArrayType.Type //xxx.Type存放的是xxx.self
ttt = Array<Int>.self
ttt = NSArray.self
ttt = NSMutableArray.self
ttt = String.self //報(bào)錯(cuò)
小補(bǔ)充:
??傳遞多個(gè)枚舉值類(lèi)型的參數(shù)(包裝成數(shù)組): [xx,xx...]
func run(){
addObserver(self, forKeyPath:"age", options: [.old,.new], context:nil)
}