Swfit-04.類,元類,錯誤處理,泛型,拓展。。。

tree_23.jpg
  • 31. X.self、X.Type、AnyClass
    • X.self(對應(yīng)OC中的類對象)是一個(gè)元類型(metadata)的指針,metadata存放著類型相關(guān)信息
    • X.self屬于X.Type類型(對應(yīng)OC中的元類對象)
class Person {}
class Student : Person {}
var perType: Person.Type = Person.self 
var stuType: Student.Type = Student.self 
perType = Student.self

var anyType: AnyObject.Type = Person.self 
anyType = Student.self

public typealias AnyClass = AnyObject.Type 
var anyType2: AnyClass = Person.self 
anyType2 = Student.self

var per = Person()
var perType = type(of: per) // Person.self 
print(Person.self == type(of: per)) // true

  
//元類型的應(yīng)用
class Animal { required init() {} } 
class Cat : Animal {}
class Dog : Animal {}
class Pig : Animal {}
func create(_ clses: [Animal.Type]) -> [Animal] { 
    var arr = [Animal]()
    for cls in clses {
        arr.append(cls.init()) 
    }
    return arr 
}
print(create([Cat.self, Dog.self, Pig.self]))
  • Swift還有個(gè)隱藏的基類:Swift._SwiftObject 源碼連接
  • 32.大寫Self
Self
// Self代表當(dāng)前類型
class Person {
    var age = 1
    static var count = 2
    func run() {
        print(self.age) // 1
        print(Self.count) // 2 等價(jià)于Person.count
    }
}
// Self一般用作返回值類型,限定返回值跟方法調(diào)用者必須是同一類型(也可以作為參數(shù)類型)
protocol Runnable { 
    func test() -> Self
}
class Person : Runnable {
    required init() {}
    func test() -> Self { 
        type(of: self).init() 
    } 
}
class Student : Person {}
var p = Person() 

// Person 
print(p.test())

var stu = Student() 
// Student 
print(stu.test())
  • 33.錯誤處理
    • 自定義錯誤:
// Swift中可以通過Error協(xié)議自定義運(yùn)行時(shí)的錯誤信息
enum SomeError : Error {
    case illegalArg(String) 
    case outOfBounds(Int, Int) 
    case outOfMemory
}
// 函數(shù)內(nèi)部通過throw拋出自定義Error,可能會拋出Error的函數(shù)必須加上throws聲明
 func divide(_ num1: Int, _ num2: Int) throws -> Int { 
    if num2 == 0 {
        throw SomeError.illegalArg("0不能作為除數(shù)")
    }
    return num1 / num2
}
// 需要使用try調(diào)用可能會拋出Error的函數(shù)
var result = try divide(20, 10)
  • 處理Error的3種方式:

1 通過do-catch捕捉Error
2 不捕捉Error,在當(dāng)前函數(shù)增加throws聲明,Error將自動拋給上層函數(shù), 如果最頂層函數(shù)(main函數(shù))依然沒有捕捉Error,那么程序?qū)⒔K止
3 可以使用try?、try!調(diào)用可能會拋出Error的函數(shù),這樣就不用去處理Error

  • 拋出Error后,try下一句直到作用域結(jié)束的代碼都將停止運(yùn)行

  • rethrows
    rethrows表明:函數(shù)本身不會拋出錯誤,但調(diào)用閉包參數(shù)拋出錯誤,那么它會將錯誤向上拋

func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows { 
    print(try fn(num1, num2))
}
// Fatal error: Error raised at top level
try exec(divide, 20, 0)
  • defer
  1. defer語句:用來定義以任何方式(拋錯誤、return等)離開代碼塊前必須要執(zhí)行的代碼
  2. defer語句將延遲至當(dāng)前作用域結(jié)束之前執(zhí)行
// defer語句的執(zhí)行順序與定義順序相反
func test() {
    defer { fn1() }
    defer { fn2() }
}
test()
// fn2
// fn1
  • assert(斷言)
  1. 很多編程語言都有斷言機(jī)制:不符合指定條件就拋出運(yùn)行時(shí)錯誤,常用于調(diào)試(Debug)階段的條件判斷
  2. 默認(rèn)情況下,Swift的斷言只會在Debug模式下生效,Release模式下會忽略

增加Swift Flags修改斷言的默認(rèn)行為
p-assert-config Release:強(qiáng)制關(guān)閉斷言
p-assert-config Debug:強(qiáng)制開啟斷言

  • fatalError
  1. 如果遇到嚴(yán)重問題,希望結(jié)束程序運(yùn)行時(shí),可以直接使用fatalError函數(shù)拋出錯誤(這是無法通過do-catch捕捉的錯誤)
  2. 使用了fatalError函數(shù),就不需要再寫return
  3. 在某些不得不實(shí)現(xiàn)、但不希望別人調(diào)用的方法,可以考慮內(nèi)部使用fatalError函數(shù)
  • 34.泛型
    • 泛型可以將類型參數(shù)化,提高代碼復(fù)用率,減少代碼量
    // 泛型函數(shù)賦值給變量
    func swapValues<T>(_ a: inout T, _ b: inout T) { (a, b) = (b, a) }
    
    • 關(guān)聯(lián)類型(Associated Type)
      關(guān)聯(lián)類型的作用:給協(xié)議中用到的類型定義一個(gè)占位名稱。就是協(xié)議中泛型的實(shí)現(xiàn)
      協(xié)議中可以擁有多個(gè)關(guān)聯(lián)類型
     protocol Stackable {
         associatedtype Element // 關(guān)聯(lián)類型 
         mutating func push(_ element: Element) 
         mutating func pop() -> Element
         func top() -> Element
         func size() -> Int
     }
     class StringStack : Stackable {
         // 給關(guān)聯(lián)類型設(shè)定真實(shí)類型
         // typealias Element = String
         var elements = [String]()
         func push(_ element: String) { elements.append(element) } 
         func pop() -> String { elements.removeLast() }
         func top() -> String { elements.last! }
         func size() -> Int { elements.count } 
     }
     var ss = StringStack() 
     ss.push("Jack") 
     ss.push("Rose")
    
    • where類型約束
    protocol Stackable {
     associatedtype Element: Equatable
    }
    class Stack<E : Equatable> : Stackable { typealias Element = E }
    
    func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool 
     where S1.Element == S2.Element, S1.Element : Hashable {
     return false
    }
    
    • 協(xié)議類型的注意點(diǎn)
    • some 不透明類型應(yīng)用
     泛型解決
     // 解決方案1:使用泛型
     func get<T : Runnable>(_ type: Int) -> T { 
         if type == 0 {
             return Person() as! T
         }
         return Car() as! T
     }
     var r1: Person = get(0)
     var r2: Car = get(1)
    
     不透明類型(Opaque Type): 屏蔽內(nèi)部實(shí)現(xiàn)細(xì)節(jié)
     // 解決方案2:使用some關(guān)鍵字聲明一個(gè)不透明類型
     // some限制只能返回一種類型
     func get(_ type: Int) -> some Runnable { 
         Car() 
     } 
     var r1 = get(0)
     var r2 = get(1)
        
     // some
     // some除了用在返回值類型上,一般還可以用在屬性類型上
     protocol Runnable { associatedtype Speed }
     class Dog : Runnable { typealias Speed = Double }
     class Person {
         var pet: some Runnable {
             return Dog()
         } 
     }
    
    • 可選項(xiàng)的本質(zhì)是enum類型
     public enum Optional<Wrapped> : ExpressibleByNilLiteral { 
         case none // nil
         case some(Wrapped) // 關(guān)聯(lián)值
         public init(_ some: Wrapped) 
     }
    
     var age: Int? = .none 
     age = 10
     age = .some(20)
     age = nil
    
     var age: Int? = 10
     var age0: Optional<Int> = Optional<Int>.some(10)
     var age1: Optional = .some(10)
     var age2 = Optional.some(10)
     var age3 = Optional(10)
    
     age = nil
     age3 = .none
    
     // 兩種判斷nil的寫法
    
     switch age {
         // 默認(rèn)會解包
         case let v?:
             print("some", v)
         case nil:
             print("none")
     }
    
     switch age {
         case let .some(v):
         print("some", v) 
    
         case .none:
         print("none")
     }
    
  • 35. 關(guān)于String的本質(zhì)探索
  // 字符串長度 <= 0xF(15),字符串內(nèi)容直接存放在str1變量的內(nèi)存中。(類似OC中的tagger pointer 技術(shù))
 var str1 = "0123456789"
 
 // 字符串長度 > 0xF,字符串內(nèi)容存放在__TEXT.cstring中(常量區(qū))
 // 字符串的地址值信息存放在str2變量的后8個(gè)字節(jié)中
 var str2 = "0123456789ABCDEF"
 
 // 由于字符串長度 <= 0xF,所以字符串內(nèi)容依然存放在str1變量的內(nèi)存中
 str1.append("ABCDE")
 // 開辟堆空間
 str1.append("F")
 
 // 開辟堆空間
 str2.append("G")
  • 36.call,jmp指令區(qū)別
  • call會把他的下一條指令的地址壓入堆棧,然后跳轉(zhuǎn)到他調(diào)用的開始處,同時(shí)ret會自動彈出返回地址。

  • JMP只是簡單的跳轉(zhuǎn)
    call的本質(zhì)相當(dāng)于push+jmp ret的本質(zhì)相當(dāng)于pop+jmp

  • 37.高級運(yùn)算符
    • 溢出運(yùn)算符(Overflow Operator):
  1. Swift的算數(shù)運(yùn)算符出現(xiàn)溢出時(shí)會拋出運(yùn)行時(shí)錯誤
  2. Swift有溢出運(yùn)算符(&+、&-、&*),用來支持溢出運(yùn)算
     var min = UInt8.min
     print(min &- 1) // 255, Int8.max
     var max = UInt8.max
     print(max &+ 1) // 0, Int8.min 
     print(max &* 2) // 254, 等價(jià)于 max &+ max
     // 逐漸遞增
     UInt8.min 0
     UInt8.max 255
    
    • 運(yùn)算符重載(Operator Overload):
      • 類、結(jié)構(gòu)體、枚舉可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn),這個(gè)操作叫做:運(yùn)算符重載
        struct Point : Equatable {
         var x = 0, y = 0
         static func + (p1: Point, p2: Point) -> Point {
             Point(x: p1.x + p2.x, y: p1.y + p2.y)
         }
         static func - (p1: Point, p2: Point) -> Point {
             Point(x: p1.x - p2.x, y: p1.y - p2.y)
         }
         static prefix func - (p: Point) -> Point {
             Point(x: -p.x, y: -p.y)
         }
         static func += (p1: inout Point, p2: Point) {
             p1 = p1 + p2
         }
         static prefix func ++ (p: inout Point) -> Point {
             p += Point(x: 1, y: 1)
             return p
         }
         static postfix func ++ (p: inout Point) -> Point {
             let tmp = p
             p += Point(x: 1, y: 1)
             return tmp
         }
     }
    
    • Equatable:
      • 要想得知2個(gè)實(shí)例是否等價(jià),一般做法是遵守Equatable 協(xié)議,重載== 運(yùn)算符
      • 與此同時(shí),等價(jià)于重載了 != 運(yùn)算符
      • Swift為以下類型提供默認(rèn)的Equatable 實(shí)現(xiàn)
      1. 沒有關(guān)聯(lián)類型的枚舉
      2. 只擁有遵守 Equatable 協(xié)議關(guān)聯(lián)類型的枚舉
      3. 只擁有遵守 Equatable 協(xié)議存儲屬性的結(jié)構(gòu)體
      • 引用類型比較存儲的地址值是否相等(是否引用著同一個(gè)對象),使用恒等運(yùn)算符=== 、!==
    • Comparable
      • 要想比較2個(gè)實(shí)例的大小,一般做法是: 1.遵守 Comparable 協(xié)議 2.重載相應(yīng)的運(yùn)算符
      // score大的比較大,若score相等,age小的比較大 
      struct Student : Comparable {
         var age: Int
         var score: Int
         init(score: Int, age: Int) {
         self.score = score
         self.age = age 
         }
         static func < (lhs: Student, rhs: Student) -> Bool { 
             (lhs.score < rhs.score)
             || (lhs.score == rhs.score && lhs.age > rhs.age)
         }
         static func > (lhs: Student, rhs: Student) -> Bool {
             (lhs.score > rhs.score)
             || (lhs.score == rhs.score && lhs.age < rhs.age)
         }
         static func <= (lhs: Student, rhs: Student) -> Bool {
             !(lhs > rhs) 
         }
         static func >= (lhs: Student, rhs: Student) -> Bool { 
             !(lhs < rhs)
         } 
     }
    
     var stu1 = Student(score: 100, age: 20) 
     var stu2 = Student(score: 98, age: 18) 
     var stu3 = Student(score: 100, age: 20) 
     print(stu1 > stu2) // true
     print(stu1 >= stu2) // true
     print(stu1 >= stu3) // true
     print(stu1 <= stu3) // true
     print(stu2 < stu1) // true
     print(stu2 <= stu1) // true
    
    
    • 自定義運(yùn)算符(Custom Operator)
      • 可以自定義新的運(yùn)算符:在全局作用域使用operator進(jìn)行聲明
     prefix operator 前綴運(yùn)算符
     postfix operator 后綴運(yùn)算符
     infix operator 中綴運(yùn)算符 : 優(yōu)先級組
     precedencegroup 優(yōu)先級組 {
         associativity: 結(jié)合性(left\right\none)
         higherThan: 比誰的優(yōu)先級高
         lowerThan: 比誰的優(yōu)先級低
         assignment: true代表在可選鏈操作中擁有跟賦值運(yùn)算符一樣的優(yōu)先級
     }
    
     prefix operator +++
     infix operator +- : PlusMinusPrecedence 
     precedencegroup PlusMinusPrecedence {
         associativity: none
         higherThan: AdditionPrecedence 
         lowerThan: MultiplicationPrecedence 
         assignment: true
     }
    
    Apple文檔參考1
    Apple文檔參考2
    • 示例:
     struct Point {
         var x: Int, y: Int
         static prefix func +++ (point: inout Point) -> Point {
             point = Point(x: point.x + point.x, y: point.y + point.y)
             return point
         }
         static func +- (left: Point, right: Point) -> Point { 
             return Point(x: left.x + right.x, y: left.y - right.y)
         }
         static func +- (left: Point?, right: Point) -> Point {
             print("+-")
             return Point(x: left?.x ?? 0 + right.x, y: left?.y ?? 0 - right.y) 
         }
     }
     struct Person {
         var point: Point
     }
     var person: Person? = nil 
     person?.point +- Point(x: 10, y: 20)
    
  • 38. 擴(kuò)展(Extension)
    • Swift中的擴(kuò)展,有點(diǎn)類似于OC中的分類(Category)

    • 擴(kuò)展可以為枚舉、結(jié)構(gòu)體、類、協(xié)議添加新功能

    • 可以添加方法、計(jì)算屬性、下標(biāo)、(便捷)初始化器、嵌套類型、協(xié)議等等

    • 擴(kuò)展不能辦到的事情:

    不能覆蓋原有的功能
    不能添加存儲屬性,不能向已有的屬性添加屬性觀察器
    不能添加父類
    不能添加指定初始化器,不能添加反初始化器
    ...

    • 協(xié)議拓展
      擴(kuò)展可以給協(xié)議提供默認(rèn)實(shí)現(xiàn),也間接實(shí)現(xiàn)『可選協(xié)議』的效果
      擴(kuò)展可以給協(xié)議擴(kuò)充『協(xié)議中從未聲明過的方法』
    • 注意下面代碼的打印信息:
     protocol TestProtocol {
         func test1()
     }
     extension TestProtocol {
         func test1() { 
             print("TestProtocol test1")
         }
         func test2() {
             print("TestProtocol test2")
         }
     }
     class TestClass : TestProtocol {
         func test1() { 
             print("TestClass test1") 
         } 
         func test2() { 
             print("TestClass test2") 
         }
     }
     var cls = TestClass()
     cls.test1() // TestClass test1 
     cls.test2() // TestClass test2
    
     var cls2: TestProtocol = TestClass() 
     cls2.test1() // TestClass test1 
     cls2.test2() // TestProtocol test2
    
    • 泛型拓展:
        // 符合條件才擴(kuò)展(只有Stack中的元素遵守Equatable協(xié)議,拓展才有效)
      extension Stack : Equatable where E : Equatable {
        static func == (left: Stack, right: Stack) -> Bool { 
            left.elements == right.elements
        } 
      }
      
  • 39.訪問控制(Access Control)
    • 在訪問權(quán)限控制這塊,Swift提供了5個(gè)不同的訪問級別(以下是從高到低排列, 實(shí)體指被訪問級別修飾的內(nèi)容)

open:允許在定義實(shí)體的模塊、其他模塊中訪問,允許其他模塊進(jìn)行繼承、重寫(open只能用在類、類成員上)
public:允許在定義實(shí)體的模塊、其他模塊中訪問,不允許其他模塊進(jìn)行繼承、重寫
internal:只允許在定義實(shí)體的模塊中訪問,不允許在其他模塊中訪問
fileprivate:只允許在定義實(shí)體的源文件中訪問
private:只允許在定義實(shí)體的封閉聲明中訪問
絕大部分實(shí)體默認(rèn)都是internal 級別

  • 訪問級別的使用準(zhǔn)則:一個(gè)實(shí)體不可以被更低訪問級別的實(shí)體定義

1.元祖,泛型都以最低那個(gè)為準(zhǔn)
2.協(xié)議實(shí)現(xiàn)不得小于協(xié)議和類中的較小的那個(gè)
3.枚舉不能每項(xiàng)單獨(dú)定義
4.public 限定作用域內(nèi)部默認(rèn)是internal
5.required初始化器 ≥ 它的默認(rèn)訪問級別

  • 直接在全局作用域下定義的private等價(jià)于fileprivate
  • 40.內(nèi)存管理
  • 跟OC一樣,Swift也是采取基于引用計(jì)數(shù)的ARC內(nèi)存管理方案(針對堆空間)
  • Swift的ARC中有3種引用:
    • 1.強(qiáng)引用(strong reference):默認(rèn)情況下,引用都是強(qiáng)引用

    • 2.弱引用(weak reference):通過weak定義弱引用

      • 必須是可選類型的var,因?yàn)閷?shí)例銷毀后,ARC會自動將弱引用設(shè)置為nil
      • ARC自動給弱引用設(shè)置nil時(shí),不會觸發(fā)屬性觀察器
    • 3.無主引用(unowned reference):通過unowned定義無主引用

      • 不會產(chǎn)生強(qiáng)引用,實(shí)例銷毀后仍然存儲著實(shí)例的內(nèi)存地址(類似于OC中的unsafe_unretained)
      • 試圖在實(shí)例銷毀后訪問無主引用,會產(chǎn)生運(yùn)行時(shí)錯誤(野指針)
        ? Fatal error: Attempted to read an unowned reference but object 0x0 was already deallocated
    • inout輸入輸出參數(shù)時(shí),注意內(nèi)存訪問沖突問題

    • 內(nèi)存訪問沖突(Conflicting Access to Memory)

內(nèi)存訪問沖突會在兩個(gè)訪問滿足下列條件時(shí)發(fā)生:
至少一個(gè)是寫入操作
它們訪問的是同一塊內(nèi)存
它們的訪問時(shí)間重疊(比如在同一個(gè)函數(shù)內(nèi))

    // 不存在內(nèi)存訪問沖突
    func plus(_ num: inout Int) -> Int { num + 1 } var number = 1
    number = plus(&number)

    // 存在內(nèi)存訪問沖突
    // Simultaneous accesses to 0x0, but modification requires exclusive access var step = 1
    func increment(_ num: inout Int) { num += step }
    increment(&step)

    // 解決內(nèi)存訪問沖突
    var copyOfStep = step 
    increment(&copyOfStep) 
    step = copyOfStep

以上均根據(jù)CoderMJLee老師的視頻及資料整理,祝小碼哥教育越來越好,特此感謝!!!

如有侵權(quán),請聯(lián)系刪除fm939071955@163.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評論 2 372

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