Kotlin (五)在集合里面感受Lambda

5.1 簡化表達(dá)

舉個Android里面最常用的例子,java總普遍的用法

view.setOnClickListener(new OnClickListener(){
  @Override
  public void onClick(View v){
  ...  
  }
})

翻譯成kotlin并且簡化

view.setOnClickListener(object:OnClickListener {
            override fun void onClick(v:View){
                ...
            }
        })

按照J(rèn)ava 單一抽象方法OnClickListener 可以用Kotlin函數(shù)替代
fun setOnclickListener(listener:(View)->Unit)
->Lambda

view.setOnClickListener({
沉御。塘娶。。
        })
-> kotlin語法糖衅鹿,listener是唯一的參數(shù)毅厚,所以可以省略括號

view.setOnClickListener{
塞颁。。吸耿。
        }

帶有接收者的Lambda

View 接收者類型擴展invisible方法

fun View.invisible(){
    visibility = View.INVISIBLE
}

接收者函數(shù)類型


val sum:Int.(Int)->Int = { other ->plus(other)}

fun main() {
    println(2.sum(1))
}

int型變量調(diào)用sum傳入一個int型變量參數(shù)祠锣,進(jìn)行plus操作

官網(wǎng)一個小例子

class HTML{
    fun body(){
        println("Test custom HTML")
    }
}
fun html(init:HTML.()->Unit):HTML{
    val html=HTML()
    html.init()
    return html
}

// 調(diào)用
html{
        body()
    }
with 和 apply

作用:再寫Lambda時候,省略需要多次書寫的對象名咽安,默認(rèn)用this指向它

Android中我們會給視圖控件綁定屬性伴网。with例子

fun bindData(bean:ContentBean){
        val titleTv = findViewById<TextView>(R.id.titleTv)
        val contentTv = findViewById<TextView>(R.id.contentTv)
        with(bean){
            titleTv.text = this.title
            contentTv.text = this.content
            titleTv.textSize = this.titleFontSize
            contentTv.textSize = this.contentFontSize
        }
    }

不用with會寫很多重復(fù)的bean
with在kotlin中的定義

 public inline fun <T, R> with(receiver: T, block: T.() -> R): R 

第一個參數(shù)是一個接收者,第二個參數(shù)是一個創(chuàng)建這個類型的block妆棒。因此在接收者調(diào)用block的時候可以在Lambda直接使用this代替bean

看下apply 的寫法

fun bindData(bean:ContentBean){
        val titleTv = findViewById<TextView>(R.id.titleTv)
        val contentTv = findViewById<TextView>(R.id.contentTv)
       
        bean.apply {
            titleTv.text = this.title
            contentTv.text = this.content
            titleTv.textSize = this.titleFontSize
            contentTv.textSize = this.contentFontSize
        
        }
    }

apply 的定義

public inline fun <T> T.apply(block: T.() -> Unit): T 

直接聲明了一個T的擴展澡腾,block參數(shù)是一個返回Unit類型的函數(shù)

with的block返回自由的類型沸伏。with和apply很多情況可以互相替代

5.2 集合的高階函數(shù)API

map 簡化

java8 之前的遍歷

int[] list = {1,2,3,4,5,6};
        int newList[] = new int[list.length];
        for (int i = 0; i < list.length; i++) {
            newList[i] = list[i] * 2;
        }

java8

 int newList[] = Arrays.stream(list).map(x-> x*2).toArray();

kotlin

val list = listOf(1,2,3,4,5,6);
val newList = list.map{it*2}

map 后面的表達(dá)式就是一個匿名帶參的函數(shù), map接收函數(shù)

fun foo3(bar:Int) = bar * 2
val newList2 = list.map { foo(it) }

map 接收函數(shù),然后將集合每個元素用這個函數(shù)操作动分,將操作結(jié)果返回毅糟,最后生成一個新的集合

map源代碼

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}

首先定義了map的擴展方法,他的實現(xiàn)主要依賴mapTo澜公。兩個參數(shù)姆另,第一個MutableCollection 集合,第二個是一個方法 (transform: (T) -> R)坟乾。就是將transform方法產(chǎn)生的結(jié)果添加到新集合里面去迹辐,返回一個新集合,避免我們for并且產(chǎn)生臨時變量

filter甚侣、count 集合篩選
data class Student(val name:String,val age:Int,val sex:String,val score:Int)
val jielun = Student("jielun",30,"m",85);
val david = Student("david",35,"f",80);
val lilei = Student("lilei",32,"m",90);
val lili = Student("",31,"m",97);
val jack = Student("jack",18,"m",92);
val pan = Student("pan",20,"m",82);
val students = listOf(jielun,david,lilei,lili,jack,pan)
val mstudents= students.filter { it.sex == "m" }

看下filter源碼

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C {
    for (element in this) if (predicate(element)) destination.add(element)
    return destination
}

看完map源碼filter就比較好理解明吩,依賴filterTo,接收兩個參數(shù),第一個MutableCollection 集合渺绒,第二個 predicate: (T) -> Boolean 返回boolean的函數(shù)(Lambda表達(dá)式)函數(shù)返回true保留否則丟棄

其他過率方法還有
filterNot,過率掉滿足條件的
filterNotNull,過率掉null元素
count,統(tǒng)計滿足條件的元素個數(shù)----顯得到滿足條件列表再統(tǒng)計贺喝,效率有點低

val stuCount= students.filter { it.sex == "m" }.size

sumBy菱鸥、sum宗兼、fold、reduce 別樣的求和方式

java中我們做法是for然后累加氮采,用sumBy 一行

val scoleTotal = students.sumBy { it.score }

拿最開始的list的int數(shù)組求和殷绍,sum和sumBy差不多

val total = list.sum()
val total2 = list.sumBy { it }
fold 是一個比較強的API ,先看下實現(xiàn)
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
    var accumulator = initial
    for (element in this) accumulator = operation(accumulator, element)
    return accumulator
}

fold 接收兩個參數(shù)鹊漠,第一個主到,initial 初始值,第二個是一個operation函數(shù)躯概。 實現(xiàn)的時候通過for遍歷集合每個元素登钥,每次都調(diào)用operation函數(shù)---也有兩個參數(shù),第一個是上一次調(diào)用這個函數(shù)的結(jié)果(第一次使用initial出事值)娶靡,第二個參數(shù)就是當(dāng)前遍歷的元素牧牢。
如何使用

val foldTotal = students.fold(0){acumulator,student->acumulator+student.score}

fold很好的利用了遞歸思想

reduce 和 fold很相似,唯一區(qū)別沒有初始值,看下源碼

public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
    val iterator = this.iterator()
    if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
    var accumulator: S = iterator.next()
    while (iterator.hasNext()) {
        accumulator = operation(accumulator, iterator.next())
    }
    return accumulator
}

如果我們不需要初始值姿锭,那么可以用reduce

val reduceTotal = students.reduce{acumulator,student->acumulator+student.score}

groupBy 分組

通常我們用java 寫很多for和if進(jìn)行循環(huán)和條件判斷塔鳍,kotlin groupBy提供了語法糖

    students.groupBy { it.sex }

返回 Map<String,List<Student>>

{m=[Student(name=jielun, age=30, sex=m, score=85), Student(name=lilei, age=32, sex=m, score=90), Student(name=, age=31, sex=m, score=97), Student(name=jack, age=18, sex=m, score=92), Student(name=pan, age=20, sex=m, score=82)], f=[Student(name=david, age=35, sex=f, score=80)]}

扁平化--處理嵌套集合:flatMap,flatten

將list2 變成和前面list一樣的普通集合

val list2 = listOf(listOf(jielun, david), listOf(lilei, lili, jack), listOf(pan))
 println(list2.flatten())
>>>>>輸出
[Student(name=jielun, age=30, sex=m, score=85), Student(name=david, age=35, sex=f, score=80), Student(name=lilei, age=32, sex=m, score=90), Student(name=, age=31, sex=m, score=97), Student(name=jack, age=18, sex=m, score=92), Student(name=pan, age=20, sex=m, score=82)]

看下源碼

public fun <T> Iterable<Iterable<T>>.flatten(): List<T> {
    val result = ArrayList<T>()
    for (element in this) {
        result.addAll(element)
    }
    return result
}

就是循環(huán)遍歷多個集合合并成了一個集合

如果我們需要得到的是加工一下的集合 flatMap

    list3.flatMap { it.map {it.name} }
>>>>>輸出
[jielun, david, lilei, , jack, pan]

看下flatMap源碼

public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}

flatMapTo 接收兩個參數(shù),第一個為一個列表呻此,改列表是一個空列表轮纫。另外一個是一個函數(shù)。改函數(shù)返回一個序列焚鲜。
遍歷集合的元素掌唾,然后將集合元素傳入transform的到一個列表放前,將列表元素添加到空列表destination中,這樣經(jīng)過transform函數(shù)處理的扁平化列表糯彬。

如果需要扁平化處理集合flattern就好犀斋,需要對元素加工那么用flatMap

5.3 集合的相關(guān)設(shè)計

2020-12-26 17.34.11.png

1.list 是一個可以重復(fù)的列表,元素存儲方式是線性存儲

    println(listOf(1,2,3,4,5,6))
>>>>
[1, 2, 3, 4, 4, 6]

  1. map 沒有實現(xiàn)Iterator和Collection情连。Map用來表示鍵值對元素集合叽粹,鍵不能重復(fù)
    println(mapOf(1 to 1 ,2 to 2,3 to 3,3 to 4))
>>>
{1=1, 2=2, 3=4}

  1. Set 表示一個補課重復(fù)的集合。實現(xiàn)有兩種HashSet 是Hash散列存儲無序和TreeSet 底層是二叉樹却舀,有序虫几。我們一般說的是無序
    println(setOf(1,2,3,3,4,4,5))
>>>
[1, 2, 3, 4, 5]

可變集合與只讀集合

kotlin 雖然是基于java但是做了改動,分為可變集合和不可變集合

  1. 可變集合挽拔,都有一個前綴“Mutable”
val mutableList = mutableListOf(1,2,3,4)
    mutableList[0] = 0
    println(mutableList)
>>>>
[0, 2, 3, 4]

2 只讀集合
val list = listOf(1,2,3,4) 如果嘗試改變編譯器報錯

特殊情況:被改

val writeList = mutableListOf(1,2,3,4,5)
    val readList:List<Int> = writeList
    writeList[0] = 0
    println(readList)

>>> 
[0, 2, 3, 4, 5]

和java互相操作

-》java

public static List<Integer> fooJava(List<Integer> list){
        for (int i = 0; i < list.size(); i++) {
            list.set(i,list.get(i) * 2);
        }
        return list;
    }

-》kotlin
fun bar(list:List<Int>){
    println(fooJava(list))
}

->
val list = listOf(1,2,3,4)
    bar(list)
    println(list)

》》》
[2, 4, 6, 8]
[2, 4, 6, 8]

傳入的list被改變了

5.4 惰性集合

如果集合元素數(shù)量比較大辆脸,使用上線的操作效率比較低

通過序列化提高效率
val list = listOf(1,2,3,4)
list.filter{it > 2}.map{it * 2}
這樣會操作兩個臨時集合先filter,然后返回集合在用map處理產(chǎn)生新的集合
如果filter處理數(shù)據(jù)量大螃诅,開銷就很大

使用序列
    list.asSequence().filter{it > 2}.map{it * 2}

中間操作

list.asSequence().filter{
        println("filter$it")
        it > 2
    }.map{
        println("map$it")
        it * 2
    }

什么也沒輸出啡氢,知道末尾加上“.toList()”才輸出了結(jié)果

末端操作
toList() 就是末端操作,就是鏈?zhǔn)秸{(diào)用最后需要輸出結(jié)果而不是序列化的東西术裸。
對比asSequence 和不加輸出的結(jié)果

list.asSequence().filter{
        println("filter($it)")
        it > 2
    }.map{
        println("map($it)")
        it * 2
    }.toList()
>>>>>>>>>>>
filter(1)
filter(2)
filter(3)
map(3)
filter(4)
map(4)

所有的中間操作被執(zhí)行

ilter{
        println("filter($it)")
        it > 2
    }.map{
        println("map($it)")
        it * 2
    }
>>>>>>>>
filter(1)
filter(2)
filter(3)
filter(4)
map(3)
map(4)

普通的鏈?zhǔn)秸{(diào)用先執(zhí)行玩filter在執(zhí)行map倘是。所以建議能先用filter的盡量先用filter。

序列可以是無限的

惰性計算最大的好處就是構(gòu)造出來一個無限的數(shù)據(jù)類型袭艺。

// 創(chuàng)造無限序列
    val naturalNumList = generateSequence(0){it +1 }
    println(naturalNumList.takeWhile { it<=9 }.toList())
>>>> 

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
雖然不能窮舉狀態(tài)搀崭,但是我們可以通過條件控制我們想要多少數(shù)據(jù)。給我們一個無限的感覺

和 java8 Stream對比

  1. java8 使用函數(shù)式API
    上面students 學(xué)生按照性別篩選
students.stream().filter(it -> it.sex == "m").collect(toList());

類似kotlin的序列猾编,java需要將集合轉(zhuǎn)換成stream流瘤睹,操作完成后,還要將stream轉(zhuǎn)換為List答倡,java8這種也是惰性計算的

  1. java8 的stream是一次性的
    如果創(chuàng)建了一個stream轰传,在這個stream上只能遍歷一次,這個流就被消費掉瘪撇。必須創(chuàng)建新的stream才能再次遍歷
    students.stream().filter(it -> it.sex == "m").collect(toList());
    students.stream().filter(it -> it.sex == "f").collect(toList());
    3.Stream 能夠并行處理數(shù)據(jù)(kotlin 目前貌似還不行)
        students.parallelStream().filter(it -> it.sex == "m").collect(toList());

多核架構(gòu)可以并行處理

5.4 內(nèi)聯(lián)函數(shù)

Lambda會帶來一定的開銷获茬。內(nèi)聯(lián)函數(shù)主要是針對Lambda的優(yōu)化。
java卻不需要设江,因為java7之后jvm引入了invokedynamic的技術(shù)锦茁,他會自動做lambda優(yōu)化

優(yōu)化Lambda
Lambda雖然語法簡單,但是在Kotlin每聲明一個Lambda就會產(chǎn)生一個匿名函類叉存,該匿名類包含一個invoke方法码俩,作為Lambda的調(diào)用方法,每次調(diào)用還會創(chuàng)建一個對象歼捏。因為Kotlin主要是對Android的開發(fā)語言稿存,Kotlin在Android中必須引入某有方法來優(yōu)化笨篷,就是內(nèi)聯(lián)函數(shù)

1.java的Invokedynamic

與kotlin這種再編譯器通過硬編碼生成Lambda轉(zhuǎn)換類機制不同,java在se7 之后通過invokedynamic實現(xiàn)了在運行期才產(chǎn)生相應(yīng)翻譯代碼瓣履。在invokedynamic 被調(diào)用的時候會產(chǎn)生一個匿名類替換中間代碼invokedynamic率翅,后續(xù)會直接使用這個匿名類。

  • 因為運行時候產(chǎn)生袖迎,字節(jié)碼只能看到固定的invokedynamic冕臭,需要靜態(tài)生成類的個數(shù)及字節(jié)碼大小顯著減小。
  • 編譯時候?qū)懰雷止?jié)碼不同燕锥,利用invokedynamic可以把實際的翻譯策略隱藏在jdk庫中辜贵,提高了靈活性,向后兼容归形,后期可以繼續(xù)對翻譯策略優(yōu)化
  • JMM天然支持針對這種方式Lambda的翻譯和優(yōu)化托慨,開發(fā)者開發(fā)時候不需要關(guān)心這些優(yōu)化。

2 內(nèi)聯(lián)函數(shù)
Kotlin 為了Android要兼容java se6 所以不能采用invokedynamic暇榴。
采用了另一種解決方案內(nèi)聯(lián)函數(shù)厚棵。c++和C#等語言也支持這種特性。簡單說可以用inline關(guān)鍵字來修飾函數(shù)蔼紧。這些函數(shù)體編譯期間被嵌入到每一個被調(diào)用的地方婆硬,減少額外生成匿名類和減少時間開銷。

我們看一個普通自定義高階函數(shù)foo歉井,接受一個類型()->Unit 的Lambda

fun foo(block:()->Unit){
    println("before block")
    block()
    println("after block")
}

fun main() {
    foo {
        println("dive into kotlin...")
    }
}

反編譯查看

public final class KT內(nèi)聯(lián)函數(shù)Kt {
   public static final void foo(@NotNull Function0 block) {
      Intrinsics.checkParameterIsNotNull(block, "block");
      String var1 = "before block";
      boolean var2 = false;
      System.out.println(var1);
      block.invoke();
      var1 = "after block";
      var2 = false;
      System.out.println(var1);
   }

   public static final void main() {
      foo((Function0)null.INSTANCE);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

調(diào)用foo產(chǎn)生一個Function0的類型的block類柿祈,然后通過invoke方法執(zhí)行哈误,這樣會增加額外的開銷哩至。我們給foo函數(shù)加上inline修飾符

public final class KT內(nèi)聯(lián)函數(shù)Kt {
   public static final void foo(@NotNull Function0 block) {
      int $i$f$foo = 0;
      Intrinsics.checkParameterIsNotNull(block, "block");
      String var2 = "before block";
      boolean var3 = false;
      System.out.println(var2);
      block.invoke();
      var2 = "after block";
      var3 = false;
      System.out.println(var2);
   }

   public static final void main() {
      int $i$f$foo = false;
      String var1 = "before block";
      boolean var2 = false;
      System.out.println(var1);
      int var3 = false;
      String var4 = "dive into kotlin...";
      boolean var5 = false;
      System.out.println(var4);
      var1 = "after block";
      var2 = false;
      System.out.println(var1);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

上面集合高階函數(shù)API也是用內(nèi)聯(lián)函數(shù)實現(xiàn)的,所以內(nèi)聯(lián)函數(shù)優(yōu)化上很有必要蜜自。

內(nèi)聯(lián)函數(shù)不是萬能菩貌,不要隨便用
對于普通函數(shù)沒必要用內(nèi)聯(lián)
避免有大量函數(shù)體的函數(shù)內(nèi)聯(lián),會導(dǎo)致過多字節(jié)碼量
一旦一個函數(shù)被內(nèi)聯(lián)重荠,就不能獲取閉包的私有成員箭阶。除非聲明為internal

noinline 避免函數(shù)參數(shù)被內(nèi)聯(lián)

有時候函數(shù)需要接收多個參數(shù),我們只想讓Lambda參數(shù)內(nèi)聯(lián)戈鲁。我們可以noinline加到不想內(nèi)聯(lián)參數(shù)的開頭

做個測試

inline fun foo(block:()->Unit,noinline block2:()->Unit){
    println("before block")
    block()
    block2()
    println("after block")
}

fun main() {
    foo ({
        println("dive into kotlin inline...")
    },{
        println("no inline...")
    })
}

對比查看字節(jié)碼

public final class KT內(nèi)聯(lián)函數(shù)Kt {
   public static final void foo(@NotNull Function0 block, @NotNull Function0 block2) {
      int $i$f$foo = 0;
      Intrinsics.checkParameterIsNotNull(block, "block");
      Intrinsics.checkParameterIsNotNull(block2, "block2");
      String var3 = "before block";
      boolean var4 = false;
      System.out.println(var3);
      block.invoke();
      block2.invoke();
      var3 = "after block";
      var4 = false;
      System.out.println(var3);
   }

   public static final void main() {
      Function0 block2$iv = (Function0)null.INSTANCE;
      int $i$f$foo = false;
      String var2 = "before block";
      boolean var3 = false;
      System.out.println(var2);
      int var4 = false;
      String var5 = "dive into kotlin inline...";
      boolean var6 = false;
      System.out.println(var5);
      block2$iv.invoke();
      var2 = "after block";
      var3 = false;
      System.out.println(var2);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

可以看到block2 沒有被內(nèi)聯(lián)

非局部返回
fun foo(){
    println("before local return")
    localReturn()
    println("after local return")
    return
}

fun localReturn() {
    return
}

fun main() {
    foo()
}
>>>>>輸出
before local return
after local return

localReturn 沒有起作用

fun foo(returnning:()->Unit){
    println("before local return")
    returnning()
    println("after local return")
    return
}

fun main() {
    foo{return}
------報錯
}

報錯了仇参,Lambda表達(dá)式正常情況不能return,修改加inline

inline fun foo(returnning:()->Unit){
    println("before local return")
    returnning()
    println("after local return")
    return
}

fun main() {
    foo{return}
}
》》》》》
before local return

中間返回了,因為inline lamba 被替代婆殿,所以return生效

crossinline

為了避免帶有return的Lambda參數(shù)產(chǎn)生破壞诈乒,可以阻止此類問題,用crossinline關(guān)鍵字修飾

fun main() {
------這里報錯
    foo{return}
//    testfoo { return@testfoo }
}
inline fun testfoo(crossinline returnning:()->Unit){
    println("before local return")
    returnning()
    println("after local return")
    return
}
具體化參數(shù)類型 reified

由于Kotlin也有泛型擦除機制婆芦,我們無法獲得一個參數(shù)的類型怕磨。然而喂饥,由于內(nèi)聯(lián)函數(shù)直接在字節(jié)碼生成相應(yīng)函數(shù)體現(xiàn),我們又可以獲得具體類型肠鲫。我們可以用reifield修飾符實現(xiàn)

fun main() {
    getType<Int>()
}

inline fun <reified T>getType(){
    println(T::class)
}
>>>>>
class java.lang.Integer (Kotlin reflection is not available)

這個在Android里比較有用

inline fun <reified T:Activity> Activity.startActivity(){
    startActivity(this,T::class.java)
}

調(diào)用员帮,簡化代碼
        startActivity<MainActivity>()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者导饲。
  • 序言:七十年代末捞高,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子渣锦,更是在濱河造成了極大的恐慌棠枉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泡挺,死亡現(xiàn)場離奇詭異辈讶,居然都是意外死亡,警方通過查閱死者的電腦和手機娄猫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門贱除,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人媳溺,你說我怎么就攤上這事月幌。” “怎么了悬蔽?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵扯躺,是天一觀的道長。 經(jīng)常有香客問我蝎困,道長录语,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任禾乘,我火速辦了婚禮澎埠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘始藕。我一直安慰自己蒲稳,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布伍派。 她就那樣靜靜地躺著江耀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诉植。 梳的紋絲不亂的頭發(fā)上祥国,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音倍踪,去河邊找鬼系宫。 笑死索昂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扩借。 我是一名探鬼主播椒惨,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼潮罪!你這毒婦竟也來了康谆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嫉到,失蹤者是張志新(化名)和其女友劉穎沃暗,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體何恶,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡孽锥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了细层。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惜辑。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疫赎,靈堂內(nèi)的尸體忽然破棺而出盛撑,到底是詐尸還是另有隱情,我是刑警寧澤捧搞,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布抵卫,位于F島的核電站,受9級特大地震影響胎撇,放射性物質(zhì)發(fā)生泄漏介粘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一创坞、第九天 我趴在偏房一處隱蔽的房頂上張望碗短。 院中可真熱鬧,春花似錦题涨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闰渔,卻和暖如春席函,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冈涧。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工茂附, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留正蛙,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓营曼,卻偏偏與公主長得像乒验,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蒂阱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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