Swift5.0比较重要的语法点归纳(二)

创建一个空数组

var someInts = [Int]()

print("someInts is of type [Int] with \(someInts.count) items.")

someInts.append(3); // someInts 现在包含一个 Int 值 

someInts = []// someInts 现在是空数组,但是仍然是 [Int] 类型的。

创建一个带有默认值的数组

var threeDoubles = Array(repeating: 0.0, count: 3)

通过两个数组相加创建一个数组

我们可以使用加法操作符(+)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)// anotherThreeDoubles 被推断为 [Double],等价于 [2.5, 2.5, 2.5]

var sixDoubles = threeDoubles + anotherThreeDoubles// sixDoubles 被推断为 [Double],等价于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

用数组字面量构造数组

var shoppingList: [String] = ["Eggs","Milk"]

由于 Swift 的类型推断机制,当我们用字面量构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。shoppingList 的构造也可以这样写

var shoppingList = ["Eggs","Milk"]

访问和修改数组

如果我们同时需要每个数据项的值和索引值,可以使用 enumerated() 方法来进行数组遍历。enumerated() 返回一个由每一个数据项索引值和数据值组成的元组。我们可以把这个元组分解成临时常量或者变量来进行遍历

for (index, value) in shoppingList.enumerated() {

    print("Item \(String(index + 1)): \(value)")

}

集合(Set)用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组

集合类型的哈希值

一个类型为了存储在集合中,该类型必须是可哈希化的——也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是 Int 类型的,相等的对象哈希值必须相同,比如 a==b,因此必须 a.hashValue == b.hashValue

你可以使用你自定义的类型作为集合的值的类型或者是字典的键的类型,但你需要使你的自定义类型遵循 Swift 标准库中的 Hashable 协议。遵循 Hashable 协议的类型需要提供一个类型为 Int的可读属性 hashValue。由类型的 hashValue 属性返回的值不需要在同一程序的不同执行周期或者不同程序之间保持相同。

因为 Hashable 协议遵循 Equatable 协议,所以遵循该协议的类型也必须提供一个“是否相等”运算符(==)的实现。这个 Equatable 协议要求任何遵循 == 实现的实例间都是一种相等的关系。也就是说,对于 a,b,c 三个值来说,== 的实现必须满足下面三种情况:

a == a(自反性)

a == b 意味着 b == a(对称性)

a == b && b == c 意味着 a == c(传递性)

创建和构造一个空的集合

var letters = Set<Character>()

print("letters is of type Set<Character> with \(letters.count) items.")

letters.insert("a")// letters 现在含有1个 Character 类型的值

letters = []// letters 现在是一个空的 Set,但是它依然是 Set<Character> 类型

用数组字面量创建集合

var favouriteGenres: Set<String> = ["Rock","Classical","Hip hop"]

一个 Set 类型不能从数组字面量中被单独推断出来,因此 Set 类型必须显式声明。然而,由于 Swift 的类型推断功能,如果你想使用一个数组字面量构造一个 Set 并且该数组字面量中的所有元素类型相同,那么你无须写出 Set 的具体类型。favoriteGenres 的构造形式可以采用简化的方式代替

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

由于数组字面量中的所有元素类型相同,Swift 可以推断出 Set<String> 作为 favoriteGenres 变量的正确类型

遍历一个集合

for genre in favouriteGenres { print("\(genre)") }

Swift 的 Set 类型没有确定的顺序,为了按照特定顺序来遍历一个 Set 中的值可以使用 sorted() 方法,它将返回一个有序数组,这个数组的元素排列顺序由操作符'<'对元素进行比较的结果来确定

for genre in favouriteGenres.sorted() { print("\(genre)") }

集合操作

使用 intersection(_:) 方法根据两个集合中都包含的值创建的一个新的集合

使用 symmetricDifference(_:) 方法根据在一个集合中但不在两个集合中的值创建一个新的集合

使用 union(_:) 方法根据两个集合的值创建一个新的集合

使用 subtracting(_:) 方法根据不在该集合中的值创建一个新的集合

let oddDigits: Set = [1,3,5,7,9]

let evenDigits: Set = [0,2,4,6,8]

let singleDigitPrimeNumbers: Set = [2,3,5,7]

oddDigits.union(evenDigits).sorted()// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

oddDigits.intersection(evenDigits).sorted()//[]

oddDigits.subtracting(singleDigitPrimeNumbers).sorted()//[1,9]

oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()// [1, 2, 9]

使用“是否相等”运算符(==)来判断两个集合是否包含全部相同的值。

使用 isSubset(of:) 方法来判断一个集合中的值是否也被包含在另外一个集合中。

使用 isSuperset(of:) 方法来判断一个集合中包含另一个集合中所有的值。

使用 isStrictSubset(of:) 或者 isStrictSuperset(of:) 方法来判断一个集合是否是另外一个集合的子集合或者父集合并且两个集合并不相等。

使用 isDisjoint(with:) 方法来判断两个集合是否不含有相同的值(是否没有交集)。

let houseAnimals: Set = ["🐶", "🐱"]

let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]

let cityAnimals: Set = ["🐦", "🐭"]

houseAnimals.isSubset(of: farmAnimals)// true

farmAnimals.isSuperset(of: houseAnimals)//true

farmAnimals.isDisjoint(with: cityAnimals)// true

字典是一种存储多个相同类型的值的容器。每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样

字典类型简化语法

Swift 的字典使用 Dictionary<Key, Value> 定义,其中 Key 是字典中键的数据类型,Value 是字典中对应于这些键所存储值的数据类型

一个字典的 Key 类型必须遵循 Hashable 协议,就像 Set 的值类型

创建一个空字典

var namesOfIntegers = [Int: String]()

namesOfIntegers[16] = "sixteen"// namesOfIntegers 现在包含一个键值对

namesOfIntegers = [:]// namesOfIntegers 又成为了一个 [Int: String] 类型的空字典

下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称

var airports: [String: String] = ["YYZ": "Toronto Pearson","DUB": "Dublin"]

这个字典语句包含了两个 String: String 类型的键值对。它们对应 airports 变量声明的类型(一个只有 String 键和 String 值的字典)所以这个字典字面量的任务是构造拥有两个初始数据项的 airport 字典

和数组一样,我们在用字典字面量构造字典时,如果它的键和值都有各自一致的类型,那么就不必写出字典的类型

var airports = ["YYZ": "Toronto Pearson","DUB": "Dublin"]

因为这个语句中所有的键和值都各自拥有相同的数据类型,Swift 可以推断出 Dictionary<String, String> 是 airports 字典的正确类型

访问和修改字典

print("The dictionary of airports contains \(airports.count) items.")

if airports.isEmpty {

print("The airports dictionary is empty.")} else{

print("The airports dictionary is not empty.")}

我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个恰当类型的键作为下标索引,并且分配恰当类型的新值

airports["LHR"] = "London"

我们也可以使用下标语法来改变特定键对应的值

airports["LHR"] = "London Heathrow"

updateValue(_:forKey:) 方法会返回对应值的类型的可选值。举例来说:对于存储 String 值的字典,这个函数会返回一个 String? 或者“可选 String”类型的值。

如果有值存在于更新前,则这个可选值包含了旧值,否则它将会是 nil

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB"){

print("The old value for DUB was \(oldValue).")}

我们也可以使用下标语法来在字典中检索特定键对应的值。因为有可能请求的键没有对应的值存在,字典的下标访问会返回对应值的类型的可选值。如果这个字典包含请求键所对应的值,下标会返回一个包含这个存在值的可选值,否则将返回 nil

if let airportName = airports["DUB"]{

print("The name of the airport is \(airportName).")}else{

print("That airport is not in the airports dictionary.")}

我们还可以使用下标语法来通过给某个键的对应值赋值为 nil 来从字典里移除一个键值对

airports["APL"] = "Apple Internation"

airports["APL"] = nil

此外,removeValue(forKey:) 方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的值或者在没有值的情况下返回 nil

if let removedValue = airports.removeValue(forKey: "DUB") {

    print("The removed airport's name is \(removedValue).")

} else {

    print("The airports dictionary does not contain a value for DUB.")

}

字典遍历

for (airportCode, airportName) in airports{

print("\(airportCode): \(airportName)")}

通过访问 keys 或者 values 属性,我们也可以遍历字典的键或者值

for airportCode in airports.keys {

    print("Airport code: \(airportCode)")

}

for airportName in airports.values {

    print("Airport name: \(airportName)")

}

如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受 Array 实例的 API 的参数,可以直接使用 keys 或者 values 属性构造一个新数组

let airportCodes = [String](airports.keys)

let airportNames = [String](airports.values)

Swift 的字典类型是无序集合类型。为了以特定的顺序遍历字典的键或值,可以对字典的 keys 或 values 属性使用 sorted() 方法

控制流

Swift 的 switch 语句比许多类 C 语言要更加强大。case 还可以匹配很多不同的模式,包括范围匹配,元组(tuple)和特定类型匹配。switch 语句的 case 中匹配的值可以声明为临时常量或变量,在 case 作用域内使用,也可以配合 where 来描述更复杂的匹配条件

for-in 循环还可以使用数字范围。下面的例子用来输出乘法表的一部分内容

for index in 1...5{

print("\(index) times 5 is \(index * 5)")}

上面的例子中,index 是一个每次循环遍历开始时被自动赋值的常量。这种情况下,index 在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用 let 关键字声明。

如果你不需要区间序列内每一项的值,你可以使用下划线(_)替代变量名来忽略这个值

let base = 3; let power = 10; var answer = 1; 

for _ in 1...power {

    answer *= base

}

print("\(base) to the power of \(power) is \(answer)")

一些用户可能在其 UI 中可能需要较少的刻度。他们可以每 5 分钟作为一个刻度。使用 stride(from:to:by:) 函数跳过不需要的标记

let minuteInterval = 5for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {

    // 每5分钟渲染一个刻度线(0, 5, 10, 15 ... 45, 50, 55)}

let hours = 12; let hourInterval = 3; 

for tickMark in stride(from: 3, through: hours, by: hourInterval) {

    // 每3小时渲染一个刻度线(3, 6, 9, 12)}

repeat-while 循环,每次在循环结束时计算条件是否符合, 和 do-while类似

条件语句

Swift 提供两种类型的条件语句:if 语句和 switch 语句。通常,当条件较为简单且可能的情况很少时,使用 if 语句。而 switch 语句更适用于条件较复杂、有更多排列组合的时候。并且 switch 在需要用到模式匹配(pattern-matching)的情况下会更有用

Switch

let someCharacter: Character = "z"

switch someCharacter{

case "a": print("The first letter of the alphabet")

case "z": print("The last letter of the alphabet")

default: print("Some other character")}

不存在隐式的贯穿

与 C 和 Objective-C 中的 switch 语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止 switch 语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用 break 语句。这使得 switch 语句更安全、更易用,也避免了漏写 break 语句导致多个语言被执行的错误

每一个 case 分支都必须包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的:

let anotherCharacter: Character = "a"

switch anotherCharacter {

case "a": // 无效,这个分支下面没有语句

case "A":

    print("The letter A")

default:

    print("Not the letter A")

}// 这段代码会报编译错误

为了让单个 case 同时匹配 a 和 A,可以将这个两个值组合成一个复合匹配,并且用逗号分开

let anotherCharacter: Character = "a"

switch anotherCharacter {

case "a", "A":

print("the letter a")

default:

print("not the letter a")}

区间匹配

case 分支的模式也可以是一个值的区间

let approximateCount = 62

let countedThings = "moons orbiting Saturn"

let naturalCount: String

switch approximateCount {

case 0:

    naturalCount = "no"

case 1..<5:

    naturalCount = "a few"

case 5..<12:

    naturalCount = "several"

case 12..<100:

    naturalCount = "dozens of"

case 100..<1000:

    naturalCount = "hundreds of"

default:

    naturalCount = "many"}

print("There are \(naturalCount) \(countedThings).")

元组

我们可以使用元组在同一个 switch 语句中测试多个值。元组中的元素可以是值,也可以是区间。另外,使用下划线(_)来匹配所有可能的值

let somePoint = (1, 1);   switch somePoint{

case (0, 0):

print("\(somePoint) is at the origin")

case (_, 0):

print("\(somePoint) is on the x-axis")

case (0, _):

    print("\(somePoint) is on the y-axis")

case (-2...2, -2...2):

    print("\(somePoint) is inside the box")

default:

    print("\(somePoint) is outside of the box")

}

值绑定(Value Bindings)

case 分支允许将匹配的值声明为临时常量或变量,并且在 case 分支体内使用 —— 这种行为被称为值绑定(value binding),因为匹配的值在 case 分支体内,与临时的常量或变量绑定

下面的例子将下图中的点 (x, y),使用 (Int, Int) 类型的元组表示,然后分类表示:

let anotherPoint = (2,0)

switch anotherPoint {

case(let x,0):

print("on the x-axis with an x value of \(x)")

case(0,let y):

print("on the y-axis with a y value of \(y)")

case let(x, y):

print("somewhere else at (\(x), \(y))")}

Where

case 分支的模式可以使用 where 语句来判断额外的条件

let yetAnotherPoint = (1, -1)

switch  yetAnotherPoint{

case let (x, y) where x==y:

print("(\(x), \(y)) is on the line x == y")

case let (x, y) where x==-y:

print("(\(x), \(y)) is on the line x == -y")

case let (x, y):

print("(\(x), \(y)) is just some arbitrary point")

}

复合型 Cases

当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个 case 后面,并且用逗号隔开。当 case 后面的任意一种模式匹配的时候,这条分支就会被匹配。并且,如果匹配列表过长,还可以分行书写

let someCharacter: Character = "e"

switch someCharacter {

case "a", "e", "i", "o", "u":

print("\(someCharacter) is a vowel")

case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":

print("\(someCharacter) is a consonant")

default:

print("\(someCharacter) is not a vowel or a consonant")}

复合匹配同样可以包含值绑定。复合匹配里所有的匹配模式,都必须包含相同的值绑定。并且每一个绑定都必须获取到相同类型的值。这保证了,无论复合匹配中的哪个模式发生了匹配,分支体内的代码,都能获取到绑定的值,并且绑定的值都有一样的类型

let stillAnotherPoint = (9, 0)

switch stillAnotherPoint{

case (let distance, 0), (0, let distance):

print("On an axis, \(distance) from the origin")

default:

print("Not on an axis")}

控制转移语句

控制转移语句改变你代码的执行顺序,通过它可以实现代码的跳转。Swift 有五种控制转移语句:

Continue

continue 语句告诉一个循环体立刻停止本次循环,重新开始下次循环。就好像在说“本次循环我已经执行完了”,但是并不会离开整个循环体

下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句

let puzzleInput = "great minds think alike"

var puzzleOutput = ""

for character in puzzleInput {

    switch character {

    case "a", "e", "i", "o", "u", " ":

        continue    

default:

        puzzleOutput.append(character)

    }

}print(puzzleOutput)

Break

break 语句会立刻结束整个控制流的执行。break 可以在 switch 或循环语句中使用,用来提前结束 switch 或循环语句

循环语句中的 break

当在一个循环体中使用 break 时,会立刻中断该循环体的执行,然后跳转到表示循环体结束的大括号(})后的第一行代码。不会再有本次循环的代码被执行,也不会再有下次的循环产生

Switch 语句中的 break

当在一个 switch 代码块中使用 break 时,会立即中断该 switch 代码块的执行,并且跳转到表示 switch 代码块结束的大括号(})后的第一行代码

贯穿(Fallthrough)

在 Swift 里,switch 语句不会从上一个 case 分支跳转到下一个 case 分支中。相反,只要第一个匹配到的 case 分支完成了它需要执行的语句,整个 switch 代码块完成了它的执行。相比之下,C 语言要求你显式地插入 break 语句到每个 case 分支的末尾来阻止自动落入到下一个 case 分支中。Swift 的这种避免默认落入到下一个分支中的特性意味着它的 switch 功能要比 C 语言的更加清晰和可预测,可以避免无意识地执行多个 case 分支从而引发的错误

如果你确实需要 C 风格的贯穿的特性,你可以在每个需要该特性的 case 分支中使用 fallthrough 关键字。下面的例子使用 fallthrough 来创建一个数字的描述语句

let integerToDescribe = 5

var description = "The number \(integerToDescribe) is"

switch integerToDescribe {

case 2, 3, 5, 7, 11, 13, 17, 19:

    description += " a prime number, and also"    

fallthrough

default:

    description += " an integer."}

print(description)

这个例子定义了一个 String 类型的变量 description 并且给它设置了一个初始值。函数使用 switch逻辑来判断 integerToDescribe 变量的值。当 integerToDescribe 的值属于列表中的质数之一时,该函数在 description 后添加一段文字,来表明这个数字是一个质数。然后它使用 fallthrough 关键字来“贯穿”到 default 分支中。default 分支在 description 的最后添加一段额外的文字,至此 switch代码块执行完了

如果 integerToDescribe 的值不属于列表中的任何质数,那么它不会匹配到第一个 switch 分支。而这里没有其他特别的分支情况,所以 integerToDescribe 匹配到 default 分支中

fallthrough 关键字不会检查它下一个将会落入执行的 case 中的匹配条件。fallthrough 简单地使代码继续连接到下一个 case 中的代码,这和 C 语言标准中的 switch 语句特性是一样的

带标签的语句

在 Swift 中,你可以在循环体和条件语句中嵌套循环体和条件语句来创造复杂的控制流结构。并且,循环体和条件语句都可以使用 break 语句来提前结束整个代码块。因此,显式地指明 break 语句想要终止的是哪个循环体或者条件语句,会很有用。类似地,如果你有许多嵌套的循环体,显式指明 continue 语句想要影响哪一个循环体也会非常有用。

为了实现这个目的,你可以使用标签(statement label)来标记一个循环体或者条件语句,对于一个条件语句,你可以使用 break 加标签的方式,来结束这个被标记的语句。对于一个循环语句,你可以使用 break 或者 continue 加标签,来结束或者继续这条被标记语句的执行。

声明一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,作为这个语句的前导关键字(introducor keyword),并且该标签后面跟随一个冒号。下面是一个针对 while 循环体的标签语法,同样的规则适用于所有的循环体和条件语句

label name: while condition {

    statements

}

这个版本的游戏使用 while 循环和 switch 语句来实现游戏的逻辑。while 循环有一个标签名 gameLoop,来表明它是游戏的主循环。

该 while 循环体的条件判断语句是 while square !=finalSquare,这表明你必须刚好落在方格25中。

gameLoop: while square != finalSquare {

    diceRoll += 1    if diceRoll == 7 { diceRoll = 1 }

    switch square + diceRoll {

    case finalSquare:

        // 骰子数刚好使玩家移动到最终的方格里,游戏结束。        break gameLoop

    case let newSquare where newSquare > finalSquare:

        // 骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子        continue gameLoop

    default:

        // 合法移动,做正常的处理        square += diceRoll

        square += board[square]

    }

}print("Game over!")

提前退出

像 if 语句一样,guard 的执行取决于一个表达式的布尔值。我们可以使用 guard 语句来要求条件必须为真时,以执行 guard 语句后的代码。不同于 if 语句,一个 guard 语句总是有一个 else 从句,如果条件不为真则执行 else 从句中的代码

funcgreet(person: [String: String]) {

    guard let name = person["name"] else {

        return    }

    print("Hello \(name)!")

    guard let location = person["location"] else {

        print("I hope the weather is nice near you.")

        return    }

    print("I hope the weather is nice in \(location).")

}

greet(person: ["name": "John"])// 输出“Hello John!”// 输出“I hope the weather is nice near you.”

greet(person: ["name": "Jane", "location": "Cupertino"])// 输出“Hello Jane!”// 输出“I hope the weather is nice in Cupertino.”

检测 API 可用性

Swift 内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的 API。

编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错

if #available(iOS 10, macOS 10.12, *) {

    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API} else {

    // 使用先前版本的 iOS 和 macOS 的 API}

if #available(平台名称 版本号, ..., *) {

    APIs 可用,语句将执行

} else {

    APIs 不可用,语句将不执行

}

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

推荐阅读更多精彩内容