Swift5.0 - day3-可选项、结构体、类

一、可选项

  • 1.1、可选项(Optional)

    • 一般也叫可选类型,它允许将值设为 nil

    • 在类型名称后面加个问号 ❓来定义一个可选型

      var name: String? = "王三"
      name = nil
      

      提示:如果定义如下

      var name:String? 等价于 var name:String? = nil
      

      可选型其实也就是要么 有值,要么是 nil

    • 默认的情况下 可选型的值在没有复制的情况下使用,值是 nil ,如上面的提示

    • 具体的举例如下

      var array = [12,3,8,20]
      func get(_ index:Int) -> Int?{
      
          if index < 0 || index >= array.count {
               return nil
          }
          return array[index]
      }
      print(get(2)) // Optional(8)
      print(get(-2)) // nil
      
  • 1.2、强制解包

    • (1)、可选项是对其他类型的一层包装,可以理解为一个盒子

      • 如果为 nil ,那么它是个空盒子

      • 如果不为 nil ,那么盒子里面装的是:被包装类型的数据

        var age:Int?   // 空盒子 nil
        age = 10       // 盒子有内容 Optional(10)
        age = nil      // 空盒子 nil
        
        可选型的盒子
    • (2)、如果想要从可选项里面取出被包装的数据(将盒子里面的东西取出来),需要用 感叹号❗️ 进行强制解包

      let age:Int? = 10
      let ageInt:Int = age!
      print(ageInt + 10)
      

      提示:如果age 为nil 进行解包会报错:Fatal error: Unexpectedly found nil while unwrapping an Optional value,如下例子

      let age:Int? = nil
      let ageInt:Int = age!
      
  • 1.3、判断可选项是否包含值

    • 具体的例子

      let number = Int("521")
      
      if number != nil{
           print("字符串转换整数成功:\(number!)")
      }else{
           print("字符串转换整数失败")
      }
      

      提示:Int("521") 可以把里面的字符串转换为整数,但是如果里面是 abc,那么就会转换失败为:nil

  • 1.4、可选项绑定 (Optional Binding)

    • 可以用 可选项 绑定来判断可选项是否包含值
      • 如果包含就自动解包,把它赋值为一个临时变量(let)或者变量(var),并返回 true,否则返回 false

      • 举例一

        if let number = Int("123"){
        
            print("字符串转换整数成功:\(number)")
            // number 是强制解包之后的 Int 值
            // number 的作用域仅限于这个大括号
        }else{
            print("字符串转换整数失败")
        }
        
      • 举例二

        enum Season:Int{
           case spring = 1,summer,autumn,winter
        }
        
        if let season = Season(rawValue: 8){
        
            switch season {
            case .spring:
                print("春天")
            default:
                print("其他季节")
            }
        }else{
           print("解包失败")
        }
        

        结果是:解包失败

  • 1.5、等价写法

    • 写法一

      if let num1 = Int("10") {
          if let num2 = Int("30") {
               if num1 < num2 && num2 < 100 {
                    print("\(num1)<\(num2)<100")
               }
          }
      }
      

      打印结果:10<30<100

    • 写法二

      if let num1 = Int("10"),
          let num2 = Int("30"),
          num1 < num2 && num2 < 100{
      
             print("\(num1)<\(num2)<100")
      }
      

      打印结果:10<30<100

      提示:牵涉到可选项的绑定的时候,不能用 && 来连接,只能用 , 来连接

  • 1.6、while选项中使用可选项绑定
    遍历数组,将遇到的正数都加起来,如果遇到负数或者非数字,停止遍历

    var array = ["1","3","40","-2","abc","29","0"]
    var index = 0
    var sum = 0
    while let num = Int(array[index]),num > 0 {
          
        sum += num
        index += 1
    }
    print("不满足条件的值是:\(array[index])")
    
  • 1.7、空合并运算符 : ?? (Nil-Coalesing Operator)

    • public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?

    • public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T

    • 解释:上面的意思也就是

      a 是可选项
      b 是可选项 或者 不是可选项
      b 跟 a 的存储类型必须相同
      如果 a 不为nil,就返回 a
      如果 a 为nil,就返回 b
      如果 b 不是可选项,返回 a 时会自动解包
      

      提示:返回类型其实是由 b 的类型决定的,在返回 a的时候,如果 b 不是可选型,那么返回 a 时,a的盒子会自动解包取出值

    • 举例如下:

      • 例一

        let a: Int? = 1 
        let b: Int? = 2 
        let c = a ?? b // c是Int? , Optional(1)
        
      • 例二

        let a: Int? = nil
        let b: Int? = 2 
        let c = a ?? b // c是Int? , Optional(2)
        
      • 例三

        let a: Int? = nil
        let b: Int? = nil
        let c = a ?? b // c是Int? , nil
        
      • 例四:a有值,b不是可选类型,a 解包 后为 b的类型

        let a: Int? = 2
        let b: Int = 1
        let c = a ?? b // c是Int , 2
        
      • 例五:a有值,b不是可选类型,a 解包 后为 b的类型

        let a: Int? = nil
        let b: Int = 2
        let c = a ?? b // c是Int , 2
        
      • 例六:如果不使用空合并运算符,我们需要如下运算

        let a: Int? = nil
        let b: Int = 2
        // 如果不使用 ?? 运算符
        let c:Int
        if let tmp = a{
             c = tmp
        }else{
             c = b
        }
        

        提示:上面的 a 类似于在可选项绑定的使用

  • 1.8、多个 ?? 一起使用

    • 例一

      let a: Int? = 1
      let b: Int = 2
      let c = a ?? b ?? 3  // c 是 Int,值为 1
      
    • 例二

      let a: Int? = nil
      let b: Int = 2
      let c = a ?? b ?? 3  // c 是 Int,值为 2
      
    • 例三

      let a: Int? = nil
      let b: Int = nil
      let c = a ?? b ?? 3  // c 是 Int,值为 3
      
  • 1.9、??if let 配合使用

    let a: Int? = nil
    let b: Int = 2
    if let c = a ?? b{
         print(c)
    }
    

    提示:上面类似于 if a != nil || b != nil

    let a: Int? = nil
    let b: Int = 2
    if let c = a, let d = b{
         print(c)
    }
    

    提示:上面类似于 if a != nil && b != nil

  • 1.10、if 语句实现登录

    func login(_ info: [String : String]) {
      
       let username: String
      
       if let tmp = info["username"] {
           username = tmp
       }else{
           print("请输入用户名")
           return
       }
    
       let password: String
       if let tmp = info["password"] {
           password = tmp
       } else {
           print("请输入密码")
           return
       }
      
       print("用户名:\(username) 密码:\(password)  登录")
    }
    

    测试

    // 用户名:jack 密码:123456 登陆ing
    login(["username" : "jack", "password" : "123456"])
    // 请输入用户名
    login(["password" : "123456"])
    // 请输入密码
    login(["username" : "jack"])
    
  • 1.11、guard 语句

    • 语法格式:

      guard  条件 else {
          // do someting .....
          // 退出当前的作用域
          // return、berak、continue、throwerror
      }
      
      • 当 guard 语句条件为 false 时,就会执行大括号里面的代码
      • 当 guard 语句条件为 true 时,就会跳过 guard 语句
      • guard 语句 特别适合用来 “提前退出”
    • 当使用 guard 语句 进行可选项绑定的时候,绑定的常量(let)、变量(var) 也能在外层作用域使用

      func login(_ info: [String : String]) {
      
          guard let username = info["username"] else {
                  print("请输入用户名")
                  return
          }
      
          guard let password = info["password"] else {
                  print("请输入密码")
                  return
          }
      
          print("用户名:\(username) 密码:\(password)  登录")
      }
      

      调用

      // 用户名:jack 密码:123456 登陆ing
      login(["username" : "jack", "password" : "123456"])
      // 请输入用户名
      login(["password" : "123456"])
      // 请输入密码
      login(["username" : "jack"])
      
  • 1.12、隐式解包(Implicitly UnwrappedOptional)

    • 在某些情况下,可选项一旦被设定值之后,就会一直拥有值

    • 在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值

    • 可以在类型后面加个 感叹号 ❗️,定义一个隐式解包的可选项

      let num1: Int! = 10
      if num1 != nil {
          print(num1 + 6) // 16
      }
      
      if let num3 = num1 {
          print(num3)
      }
      

      提示:如果用 ! 要保证有值,因为 用!的变量或者常量在使用的时候是在强制解包,不然会报错,如下

      let num1: Int! = nil
      let num2: Int = num1
      print(num2)
      

      报错:Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

  • 1.13、字符串插值

    • 如下代码的警告:String interpolation produces a debug description for an optional value; did you mean to make this explicit?

      let heigt:Int? = 29
      print("height=\(heigt)")
      
    • 处理警告的报错方式

      • 方式一:强制解包

        print("height=\(heigt!)")
        
      • 方式二:

        print("height=\(String(describing: heigt))")
        
      • 方式三:

        print("height=\(heigt ?? 0)")
        
  • 1.14、多重可选项

    • 多重可选项举例一

      var num1:Int? = 10
      var num2:Int?? = num1
      var num3:Int?? = 10
      
      print(num1 == num3)
      
      多重可选项

      可以使用 lldb 命令来查看:frame variable -R 或者 fr v -R 查看区别
      frame 内存布局 variable 变量

      可以使用 lldb 命令来查看:`frame variable -R` 或者 `fr v -R` 查看区别

    • 多重可选项举例二

      var num1:Int? = nil
      var num2:Int?? = num1
      var num3:Int?? = nil
      
      print(num1 == num3)
      
      可以使用 lldb 命令来查看

二、结构体

  • 2.1、结构体:在 Swift 标准库库中,绝大多数的公开类型都是结构体(值类型),而枚举和类(引用类型)只占很小的一部分,比如:Bool、Int、Double、String、 Array、Dictionary 等常见类型都是结构体,其中可以定义方法和属性,但其不像类一样具有继承的特性。

    struct Date {
      var year: Int
      var month: Int
      var day: Int
    }
    
    var date = Date(year: 2019, month: 6, day: 24)
    

    所有的结构体都有一个编译器自动生成的初始化器(initialier 初始化方法、构造器、构造方法),在2.1、中的调用 var date = Date(year: 2019, month: 6, day: 24) 代码 可以传入所有成员的值,以初始化所有成员(存储属性,英文名:Sored Property)

  • 2.2、结构体的初始化器

    • 编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有的成员都有初始值,如下

      struct Point {
         var x:Int
         var y:Int
      }
      
      var p1 = Point(x: 10, y: 10)
      var p2 = Point(x: 10)  // Definition conflicts with previous value
      var p3 = Point(y: 10)  // Definition conflicts with previous value
      var p4 = Point()      // Definition conflicts with previous value
      
    • 举例二

      struct Point {
         var x:Int = 0
         var y:Int
      }
      
      var p1 = Point(x: 10, y: 10)
      var p1 = Point(x: 10)  // Definition conflicts with previous value
      var p1 = Point(y: 10)  // Definition conflicts with previous value
      var p1 = Point()      // Definition conflicts with previous value
      
    • 举例三

        struct Point {
           var x:Int 
           var y:Int = 0
        }
      
        var p1 = Point(x: 10, y: 10)
        var p1 = Point(x: 10)  // Definition conflicts with previous value
        var p1 = Point(y: 10)  // Definition conflicts with previous value
        var p1 = Point()      // Definition conflicts with previous value
      
    • 举例四

        struct Point {
           var x:Int = 0
           var y:Int = 0
        }
      
        var p1 = Point(x: 10, y: 10)
        var p1 = Point(x: 10)  // Definition conflicts with previous value
        var p1 = Point(y: 10)  // Definition conflicts with previous value
        var p1 = Point()      // Definition conflicts with previous value
      
    • 思考下面能编译通过吗?

      struct Point {
         var x: Int?
         var y: Int?
      }
      
      var p1 = Point(x: 1, y: 2)
      var p2 = Point(y: 1)
      var p3 = Point(x: 2)
      var p4 = Point()
      

      结论:可以编译通过,因为 可选项都有个默认值 nil,因此可以编译通过

  • 2.3、自定义初始化器

    • 一旦在定义结构体的时候定义了初始化器,编译器就不会再帮它自动生成其他初始化器

      struct Point {
          var x: Int = 0
          var y: Int = 0
          init(x:Int,y:Int) {
             self.x = x
             self.y = y
          }
      }
      
      var p1 = Point(x: 1, y: 2)
      var p2 = Point(y: 1)  // 报错
      var p3 = Point(x: 2) // 报错
      var p4 = Point() // 报错
      
  • 2.4、窥探初始化器的本质,下面的两段代码等效

    • 第 1 段代码

      struct Point {
          var x: Int = 0
          var y: Int = 0
      }
      
      var p = Point() 
      
    • 第 2 段代码

      struct Point {
         var x: Int = 0
         var y: Int = 0
         init(x:Int,y:Int) {
            self.x = x
            self.y = y
         }
      }
      
      var p = Point() 
      
  • 2.5、结构体的内存结构

    struct Point {
          var x: Int = 0
          var y: Int = 0
          var origin: Bool = false
    }
    
    print(MemoryLayout<Point>.size)  // 17
    print(MemoryLayout<Point>.stride) // 24
    print(MemoryLayout<Point>.alignment) // 8
    

    结构体所占用的内存空间:所有存储属性内存空间之和对齐之后的结果

三、类

  • 3.1、类的定义和结构体类似,但编译体并没有为类自动生成可以传入成员值的初始化器,如下三段代码

    • 代码段一

      class Point {
          var x: Int = 0
          var y: Int = 0
      }
      
      var p1 = Point(x: 10, y: 10)  // 报错
      var p2 = Point(y: 10) // 报错
      var p3 = Point(x: 10) // 报错
      var p4 = Point()
      

      提示:类只有最简单的初始化器:类名()

    • 代码段二

      struct Point {
          var x: Int = 0
          var y: Int = 0
      }
      
      var p1 = Point(x: 10, y: 10) 
      var p2 = Point(y: 10) 
      var p3 = Point(x: 10) 
      var p4 = Point()
      
    • 代码段三


      代码段三
  • 3.2、类的初始化器

    • 如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无参数的初始化器

    • 成员的初始化是在这个初始化器中完成的

      class Point{
           var x:Int = 1
           var y:Int = 2
      }
      
      let p = Point()
      

      等效下面的代码

      class Point{
           var x:Int
           var y:Int
           init(){
               self.x = 1
               self.y = 2
           }
      }
      
      let p = Point()
      
  • 3.3、结构体与类的本质区别

    • 结构体是值类型(枚举也是值类型),类是引用类型(指针类型)

      class Size{
           var width = 1
           var height = 2
      }
      
      struct Point{
           var x = 3
           var y = 4
      }
      
      func test(){
          var size = Size()
          var point = Point()
      }
      
      上图是针对 64bit 环境
      • 前 8 个字节指向类型的信息,后8个是指向引用计数 ,最后面的16个是来存储成员变量的
  • 3.4、值类型

    • 值类型赋值给 varlet 或者给函数传参,是直接将所有的内容拷贝一份,类似于对文件进行 copy、paste操作,产生了全新的文件副本。属于深拷贝(deep copy)

      struct Point{
          var x:Int
          var y:Int
      }
      
      func test(){
      
         var p1 = Point(x: 1, y: 2)
         var p2 = p1
         p2.x = 10
         p2.y = 20
      
         print("p1.x=\(p1.x) p1.y=\(p1.y)")
      
      }
      

      打印结果是:p1.x=1 p1.y=2

  • 3.5、值类型的赋值操作

    • 例一:字符串

      var s1 = "Tom"
      var s2 = s1
      s2.append("_Jack")
      print("s1=\(s1)") // s1=Tom
      print("s2=\(s2)") // s2=Tom_Jack
      
    • 例二:数组

      var a1 = [1,2,3]
      var a2 = a1
      a2.append(4)
      print("a1=\(a1)") // a1=[1, 2, 3]
      print("a2=\(a2)") // a2=[1, 2, 3, 4]
      
    • 例三:字典

      var d1 = ["max":10,"min":20]
      var d2 = d1
      d1["other"] = 12
      d2["max"] = 30
      
      print("d1=\(d1)") // d1=["other": 12, "max": 10, "min": 20]
      print("d2=\(d2)") // d2=["max": 30, "min": 20]
      

    提示:

    • 在 Swift 标准库中,为了提升性能,String、Array、Dictionary、Set采取了Copy On Write 的技术
    • 比如:仅当有 “写” 操作的时候,才会真正执行copy操作;对于标准库值类型的赋值操作,Swift能确保最佳性能,所以没必要为了保证最佳性能来避免赋值
    • 建议:没必要做修改的尽量定义成 let
  • 3.6、值类型的赋值操作(结构体、枚举)

    struct Point{
        var x:Int
        var y:Int
    }
    
    var p1 = Point(x: 10, y: 20)
    print(p1) // Point(x: 10, y: 20)
    p1 = Point(x: 11, y: 22)
    print(p1) // Point(x: 11, y: 22)
    
  • 3.7、引用类型(类)

    • 引用赋值给 letvar 或者给函数传参,是将内存地址拷贝一份,类似于一个文件的替身(快捷方式,链接),指向的是同一个文件。属于浅拷贝(shallow copy)

      class Size{
            var width:Int
            var height:Int
            init(width:Int,height:Int) {
                 self.width = width
                 self.height = height
            }
      }
      
      var s1 = Size(width: 10, height: 20)
      var s2 = s1
      s2.width = 11
      s2.height = 22
      
      print("s1.width=\(s1.width)")
      print("s1.height=\(s1.height)")
      

      打印结果:

      s1.width=11
      s1.height=22
      
      引用类型
  • 3.8、引用类型的赋值操作

    class Size{
       var width:Int
       var height:Int
       init(width:Int,height:Int) {
           self.width = width
           self.height = height
       }
    }
    
    var s1 = Size(width: 10, height: 20)
    s1 = Size(width: 11, height: 22)
    
  • 3.9、值类型和引用类型的 let

    struct Point{
        var x:Int
        var y:Int
    }
    
    使用图
    class Size{
       var width:Int
       var height:Int
       init(width:Int,height:Int) {
              self.width = width
              self.height = height
       }
    }
    
    使用图
    • 字符串和数组的使用


  • 3.10、嵌套类型

    struct Poker {
        enum Suit:Character {
            case spades = "️",hearts = "️",diamonds = "️",clubs = "️"
        }
        enum Rank:Int {
            case two = 2,three,four,five,six,even
            case jack,queen,king,ace
        }
    }
    

    嵌套的使用: 打印是 hearts 的原始值

    print(Poker.Suit.hearts.rawValue)
    

    更多的使用

    var suit = Poker.Suit.spades
    suit = .diamonds  
      
    var rank = Poker.Rank.five
    rank = .king
    
  • 3.11、枚举、结构体、类在其内部都可以函数,称其:方法

    class Size {
        var width:Int = 1
        var height:Int = 2
        func test() {
            ......
        }
    }
    
    struct Size {
        var width:Int = 1
        var height:Int = 2
        func test() {
            ......
        }
    }
    
    enum Date{
    
        case digit(year:Int,month:Int,day:Int)
        case string(String)
        func test() {
            ......
        }
    }
    

    提示:方法是不占用实例对象内存的

  • 3.12、下面值类型与引用类型 内存结构如下

    struct Point {
         var x: Int
         var b1: Bool
         var b2: Bool
         var y: Int
    }
    
    var p = Point(x: 10, b1: true, b2: true, y: 20)
    
    MemoryLayout<Point>.stride   // 24 分配占用的内存空间大小
    MemoryLayout<Point>.size  // 24 实际用到的空间大小
    MemoryLayout<Point>.alignment  // 8 对齐参数
    
    class Size {
       var width: Int
       var b1: Bool
       var b2: Bool
       var height: Int
       init(width: Int, b1: Bool, b2: Bool, height: Int) {
           self.width = width
           self.b1 = b1
           self.b2 = b2
           self.height = height
       } 
    }
    var s = Size(width: 10, b1: true, b2: true, height: 20)
    
    MemoryLayout<Size>.stride   // 8 分配占用的内存空间大小
    MemoryLayout<Size>.size  // 8 实际用到的空间大小
    MemoryLayout<Size>.alignment  // 8 对齐参数
    

四、结构体和类的区别

  • 4.1、结构体通常用来定义一组数据类型的组合,而类则是面向对象的,其中除了可以定义属性还可以定义方法。在Swift里面类也可以,区分不太明显。
  • 4.2、值类型和引用类型的区别
    它们最大的区别在于进行数据传递的时候,值类型总是复制,值类型有数据传递,原来的实例会被复制一份,修改新的实例不能修改原始的实例;引用类型不会被复制,传递是引用,修改是自身,引用类型是通过引用计数来管理其生命周期的。
  • 4.3、在结构体里面开发者不需要自己提供构造方法,结构体会自己生成一些构造方法,而类则要求开发者自己提供构造方法。
  • 4.4、结构体不可以被继承,类可以进行继承。
  • 4.5、内存所处位置
    • 结构体的具体在哪是由创建的位置决定的,比如在func内定义的结构体是在栈空间,func是在栈空间,func在哪里是无所谓的
    • 类不管在哪里创建,对象的内存(如:类Ponit())空间一定在堆空间,因为会调用 alloc/malloc 等;指针变量(如:point = Ponit())的内存可能在其他的地方,
  • 扩展:在对值类型进行比较的时候,应使用等号运算符 ==;对引用类型进行比较操作,应使用等同运算符 === ,如下代码

    class TextClass {
    }
    var text1 = TextClass()
    var text2 = text1
    //比较结果是 true
    text1  === text2
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容