Swift函數(shù)式編程與面向協(xié)議編程

函數(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)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蹬音,一起剝皮案震驚了整個(gè)濱河市上煤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌著淆,老刑警劉巖劫狠,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異永部,居然都是意外死亡独泞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)苔埋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)懦砂,“玉大人,你說(shuō)我怎么就攤上這事≤癖欤” “怎么了罚随?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衫画。 經(jīng)常有香客問(wèn)我毫炉,道長(zhǎng),這世上最難降的妖魔是什么削罩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任瞄勾,我火速辦了婚禮,結(jié)果婚禮上弥激,老公的妹妹穿的比我還像新娘进陡。我一直安慰自己,他們只是感情好微服,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布趾疚。 她就那樣靜靜地躺著,像睡著了一般以蕴。 火紅的嫁衣襯著肌膚如雪糙麦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天丛肮,我揣著相機(jī)與錄音赡磅,去河邊找鬼。 笑死宝与,一個(gè)胖子當(dāng)著我的面吹牛焚廊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播习劫,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼咆瘟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诽里?” 一聲冷哼從身側(cè)響起袒餐,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谤狡,沒(méi)想到半個(gè)月后灸眼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡豌汇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泄隔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拒贱。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逻澳,到底是詐尸還是另有隱情闸天,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布斜做,位于F島的核電站苞氮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瓤逼。R本人自食惡果不足惜笼吟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望霸旗。 院中可真熱鬧贷帮,春花似錦、人聲如沸诱告。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)精居。三九已至锄禽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間靴姿,已是汗流浹背沃但。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留空猜,地道東北人绽慈。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像辈毯,于是被迫代替她去往敵國(guó)和親坝疼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容