go語言20小時從入門到精通(八蜓萄、 面向?qū)ο缶幊蹋?/h1>

8.1 概述

對于面向?qū)ο缶幊痰闹С諫o 語言設(shè)計得非常簡潔而優(yōu)雅隅茎。因為, Go語言并沒有沿襲傳統(tǒng)面向?qū)ο缶幊讨械闹T多概念嫉沽,比如繼承(不支持繼承辟犀,盡管匿名字段的內(nèi)存布局和行為類似繼承,但它并不是繼承)绸硕、虛函數(shù)堂竟、構(gòu)造函數(shù)和析構(gòu)函數(shù)、隱藏的this指針等玻佩。

盡管Go語言中沒有封裝出嘹、繼承、多態(tài)這些概念咬崔,但同樣通過別的方式實現(xiàn)這些特性:
封裝:通過方法實現(xiàn)
繼承:通過匿名字段實現(xiàn)
多態(tài):通過接口實現(xiàn)

8.2 匿名組合

8.2.1 匿名字段

一般情況下税稼,定義結(jié)構(gòu)體的時候是字段名與其類型一一對應(yīng),實際上Go支持只提供類型垮斯,而不寫字段名的方式郎仆,也就是匿名字段,也稱為嵌入字段兜蠕。

當匿名字段也是一個結(jié)構(gòu)體的時候扰肌,那么這個結(jié)構(gòu)體所擁有的全部字段都被隱式地引入了當前定義的這個結(jié)構(gòu)體。

//人
type Person struct {
    name string
    sex  byte
    age  int
}
//學(xué)生
type Student struct {
    Person // 匿名字段牺氨,那么默認Student就包含了Person的所有字段
    id     int
    addr   string
}

8.2.2 初始化

//人
type Person struct {
    name string
    sex  byte
    age  int
}

//學(xué)生
type Student struct {
    Person // 匿名字段狡耻,那么默認Student就包含了Person的所有字段
    id     int
    addr   string
}

func main() {
    //順序初始化
    s1 := Student{Person{"mike", 'm', 18}, 1, "sz"}
    //s1 = {Person:{name:mike sex:109 age:18} id:1 addr:sz}
    fmt.Printf("s1 = %+v\n", s1)

    //s2 := Student{"mike", 'm', 18, 1, "sz"} //err

    //部分成員初始化1
    s3 := Student{Person: Person{"lily", 'f', 19}, id: 2}
    //s3 = {Person:{name:lily sex:102 age:19} id:2 addr:}
    fmt.Printf("s3 = %+v\n", s3)

    //部分成員初始化2
    s4 := Student{Person: Person{name: "tom"}, id: 3}
    //s4 = {Person:{name:tom sex:0 age:0} id:3 addr:}
    fmt.Printf("s4 = %+v\n", s4)
}

8.2.3 成員的操作

var s1 Student //變量聲明
//給成員賦值
s1.name = "mike" //等價于 s1.Person.name = "mike"
s1.sex = 'm'
s1.age = 18
s1.id = 1
s1.addr = "sz"
fmt.Println(s1) //{{mike 109 18} 1 sz}

var s2 Student //變量聲明
s2.Person = Person{"lily", 'f', 19}
s2.id = 2
s2.addr = "bj"
fmt.Println(s2) //{{lily 102 19} 2 bj}

8.2.4 同名字段

//人
type Person struct {
    name string
    sex  byte
    age  int
}

//學(xué)生
type Student struct {
    Person // 匿名字段,那么默認Student就包含了Person的所有字段
    id     int
    addr   string
    name   string //和Person中的name同名
}

func main() {
    var s Student //變量聲明

    //給Student的name猴凹,還是給Person賦值夷狰?
    s.name = "mike"

    //{Person:{name: sex:0 age:0} id:0 addr: name:mike}
    fmt.Printf("%+v\n", s)

    //默認只會給最外層的成員賦值
    //給匿名同名成員賦值,需要顯示調(diào)用
    s.Person.name = "yoyo"
    //Person:{name:yoyo sex:0 age:0} id:0 addr: name:mike}
    fmt.Printf("%+v\n", s)
}

8.2.5 其它匿名字段

8.2.5.1 非結(jié)構(gòu)體類型

所有的內(nèi)置類型和自定義類型都是可以作為匿名字段的:

type mystr string //自定義類型

type Person struct {
    name string
    sex  byte
    age  int
}

type Student struct {
    Person // 匿名字段郊霎,結(jié)構(gòu)體類型
    int     // 匿名字段沼头,內(nèi)置類型
    mystr   // 匿名字段,自定義類型
}

func main() {
    //初始化
    s1 := Student{Person{"mike", 'm', 18}, 1, "bj"}

    //{Person:{name:mike sex:109 age:18} int:1 mystr:bj}
    fmt.Printf("%+v\n", s1)

    //成員的操作,打印結(jié)果:mike, m, 18, 1, bj
    fmt.Printf("%s, %c, %d, %d, %s\n", s1.name, s1.sex, s1.age, s1.int, s1.mystr)
}

8.2.5.2 結(jié)構(gòu)體指針類型

type Person struct { //人
    name string
    sex  byte
    age  int
}

type Student struct { //學(xué)生
    *Person // 匿名字段进倍,結(jié)構(gòu)體指針類型
    id      int
    addr    string
}

func main() {
    //初始化
    s1 := Student{&Person{"mike", 'm', 18}, 1, "bj"}

    //{Person:0xc0420023e0 id:1 addr:bj}
    fmt.Printf("%+v\n", s1)
    //mike, m, 18
    fmt.Printf("%s, %c, %d\n", s1.name, s1.sex, s1.age)

    //聲明變量
    var s2 Student
    s2.Person = new(Person) //分配空間
    s2.name = "yoyo"
    s2.sex = 'f'
    s2.age = 20

    s2.id = 2
    s2.addr = "sz"

    //yoyo 102 20 2 20
    fmt.Println(s2.name, s2.sex, s2.age, s2.id, s2.age)
}

8.3 方法

8.3.1 概述

在面向?qū)ο缶幊讨型林粒粋€對象其實也就是一個簡單的值或者一個變量,在這個對象中會包含一些函數(shù)猾昆,這種帶有接收者的函數(shù)陶因,我們稱為方法(method)。 本質(zhì)上垂蜗,一個方法則是一個和特殊類型關(guān)聯(lián)的函數(shù)楷扬。

一個面向?qū)ο蟮某绦驎梅椒▉肀磉_其屬性和對應(yīng)的操作,這樣使用這個對象的用戶就不需要直接去操作對象贴见,而是借助方法來做這些事情烘苹。

在Go語言中,可以給任意自定義類型(包括內(nèi)置類型片部,但不包括指針類型)添加相應(yīng)的方法镣衡。

?法總是綁定對象實例,并隱式將實例作為第?實參 (receiver)档悠,方法的語法如下:
func (receiver ReceiverType) funcName(parameters) (results)
參數(shù) receiver 可任意命名廊鸥。如?法中未曾使?,可省略參數(shù)名站粟。
參數(shù) receiver 類型可以是 T 或 *T黍图。基類型 T 不能是接?或指針奴烙。
不支持重載方法,也就是說剖张,不能定義名字相同但是不同參數(shù)的方法切诀。

8.3.2 為類型添加方法

8.3.2.1 基礎(chǔ)類型作為接收者

type MyInt int //自定義類型,給int改名為MyInt

//在函數(shù)定義時搔弄,在其名字之前放上一個變量幅虑,即是一個方法
func (a MyInt) Add(b MyInt) MyInt { //面向?qū)ο?    return a + b
}

//傳統(tǒng)方式的定義
func Add(a, b MyInt) MyInt { //面向過程
    return a + b
}

func main() {
    var a MyInt = 1
    var b MyInt = 1

    //調(diào)用func (a MyInt) Add(b MyInt)
    fmt.Println("a.Add(b) = ", a.Add(b)) //a.Add(b) =  2

    //調(diào)用func Add(a, b MyInt)
    fmt.Println("Add(a, b) = ", Add(a, b)) //Add(a, b) =  2
}

通過上面的例子可以看出,面向?qū)ο笾皇菗Q了一種語法形式來表達顾犹。方法是函數(shù)的語法糖倒庵,因為receiver其實就是方法所接收的第1個參數(shù)。

注意:雖然方法的名字一模一樣炫刷,但是如果接收者不一樣擎宝,那么方法就不一樣。

8.3.2.2 結(jié)構(gòu)體作為接收者

方法里面可以訪問接收者的字段浑玛,調(diào)用方法通過點( . )訪問绍申,就像struct里面訪問字段一樣:

type Person struct {
    name string
    sex  byte
    age  int
}

func (p Person) PrintInfo() { //給Person添加方法
    fmt.Println(p.name, p.sex, p.age)
}

func main() {
    p := Person{"mike", 'm', 18} //初始化
    p.PrintInfo() //調(diào)用func (p Person) PrintInfo()
}

8.3.3 值語義和引用語義
type Person struct {
    name string
    sex  byte
    age  int
}

//指針作為接收者,引用語義
func (p *Person) SetInfoPointer() {
    //給成員賦值
    (*p).name = "yoyo"
    p.sex = 'f'
    p.age = 22
}

//值作為接收者,值語義
func (p Person) SetInfoValue() {
    //給成員賦值
    p.name = "yoyo"
    p.sex = 'f'
    p.age = 22
}

func main() {
    //指針作為接收者极阅,引用語義
    p1 := Person{"mike", 'm', 18} //初始化
    fmt.Println("函數(shù)調(diào)用前 = ", p1)   //函數(shù)調(diào)用前 =  {mike 109 18}
    (&p1).SetInfoPointer()
    fmt.Println("函數(shù)調(diào)用后 = ", p1) //函數(shù)調(diào)用后 =  {yoyo 102 22}

    fmt.Println("==========================")

    p2 := Person{"mike", 'm', 18} //初始化
    //值作為接收者胃碾,值語義
    fmt.Println("函數(shù)調(diào)用前 = ", p2) //函數(shù)調(diào)用前 =  {mike 109 18}
    p2.SetInfoValue()
    fmt.Println("函數(shù)調(diào)用后 = ", p2) //函數(shù)調(diào)用后 =  {mike 109 18}
}

8.3.4 方法集

類型的方法集是指可以被該類型的值調(diào)用的所有方法的集合。

用實例實例 value 和 pointer 調(diào)用方法(含匿名字段)不受?法集約束筋搏,編譯器編總是查找全部方法仆百,并自動轉(zhuǎn)換 receiver 實參。

8.3.4.1 類型 *T 方法集

一個指向自定義類型的值的指針奔脐,它的方法集由該類型定義的所有方法組成俄周,無論這些方法接受的是一個值還是一個指針。

如果在指針上調(diào)用一個接受值的方法帖族,Go語言會聰明地將該指針解引用栈源,并將指針所指的底層值作為方法的接收者。

類型 *T ?法集包含全部 receiver T + *T ?法:

type Person struct {
    name string
    sex  byte
    age  int
}

//指針作為接收者竖般,引用語義
func (p *Person) SetInfoPointer() {
    (*p).name = "yoyo"
    p.sex = 'f'
    p.age = 22
}

//值作為接收者甚垦,值語義
func (p Person) SetInfoValue() {
    p.name = "xxx"
    p.sex = 'm'
    p.age = 33
}

func main() {
    //p 為指針類型
    var p *Person = &Person{"mike", 'm', 18}
    p.SetInfoPointer() //func (p) SetInfoPointer()

    p.SetInfoValue()    //func (*p) SetInfoValue()
    (*p).SetInfoValue() //func (*p) SetInfoValue()
}

8.3.4.2 類型 T 方法集

一個自定義類型值的方法集則由為該類型定義的接收者類型為值類型的方法組成,但是不包含那些接收者類型為指針的方法涣雕。

但這種限制通常并不像這里所說的那樣艰亮,因為如果我們只有一個值,仍然可以調(diào)用一個接收者為指針類型的方法挣郭,這可以借助于Go語言傳值的地址能力實現(xiàn)迄埃。

type Person struct {
    name string
    sex  byte
    age  int
}

//指針作為接收者,引用語義
func (p *Person) SetInfoPointer() {
    (*p).name = "yoyo"
    p.sex = 'f'
    p.age = 22
}

//值作為接收者兑障,值語義
func (p Person) SetInfoValue() {
    p.name = "xxx"
    p.sex = 'm'
    p.age = 33
}

func main() {
    //p 為普通值類型
    var p Person = Person{"mike", 'm', 18}
    (&p).SetInfoPointer() //func (&p) SetInfoPointer()
    p.SetInfoPointer()    //func (&p) SetInfoPointer()
    
    p.SetInfoValue()      //func (p) SetInfoValue()
    (&p).SetInfoValue()   //func (*&p) SetInfoValue()
}

8.3.5 匿名字段

8.3.5.1 方法的繼承

如果匿名字段實現(xiàn)了一個方法侄非,那么包含這個匿名字段的struct也能調(diào)用該方法。

type Person struct {
    name string
    sex  byte
    age  int
}

//Person定義了方法
func (p *Person) PrintInfo() {
    fmt.Printf("%s,%c,%d\n", p.name, p.sex, p.age)
}

type Student struct {
    Person // 匿名字段流译,那么Student包含了Person的所有字段
    id     int
    addr   string
}

func main() {
    p := Person{"mike", 'm', 18}
    p.PrintInfo()

    s := Student{Person{"yoyo", 'f', 20}, 2, "sz"}
    s.PrintInfo()
}

8.3.5.2 方法的重寫

type Person struct {
    name string
    sex  byte
    age  int
}

//Person定義了方法
func (p *Person) PrintInfo() {
    fmt.Printf("Person: %s,%c,%d\n", p.name, p.sex, p.age)
}

type Student struct {
    Person // 匿名字段逞怨,那么Student包含了Person的所有字段
    id     int
    addr   string
}

//Student定義了方法
func (s *Student) PrintInfo() {
    fmt.Printf("Student:%s,%c,%d\n", s.name, s.sex, s.age)
}

func main() {
    p := Person{"mike", 'm', 18}
    p.PrintInfo() //Person: mike,m,18

    s := Student{Person{"yoyo", 'f', 20}, 2, "sz"}
    s.PrintInfo()        //Student:yoyo,f,20
    s.Person.PrintInfo() //Person: yoyo,f,20
}

8.3.6 表達式

類似于我們可以對函數(shù)進行賦值和傳遞一樣,方法也可以進行賦值和傳遞福澡。

根據(jù)調(diào)用者不同叠赦,方法分為兩種表現(xiàn)形式:方法值和方法表達式。兩者都可像普通函數(shù)那樣賦值和傳參革砸,區(qū)別在于方法值綁定實例除秀,?方法表達式則須顯式傳參。

8.3.6.1 方法值

type Person struct {
    name string
    sex  byte
    age  int
}

func (p *Person) PrintInfoPointer() {
    fmt.Printf("%p, %v\n", p, p)
}

func (p Person) PrintInfoValue() {
    fmt.Printf("%p, %v\n", &p, p)
}

func main() {
    p := Person{"mike", 'm', 18}
    p.PrintInfoPointer() //0xc0420023e0, &{mike 109 18}

    pFunc1 := p.PrintInfoPointer //方法值算利,隱式傳遞 receiver
    pFunc1()                     //0xc0420023e0, &{mike 109 18}

    pFunc2 := p.PrintInfoValue
    pFunc2() //0xc042048420, {mike 109 18}
}

8.3.6.2 方法表達式

type Person struct {
    name string
    sex  byte
    age  int
}

func (p *Person) PrintInfoPointer() {
    fmt.Printf("%p, %v\n", p, p)
}

func (p Person) PrintInfoValue() {
    fmt.Printf("%p, %v\n", &p, p)
}

func main() {
    p := Person{"mike", 'm', 18}
    p.PrintInfoPointer() //0xc0420023e0, &{mike 109 18}

    //方法表達式册踩, 須顯式傳參
    //func pFunc1(p *Person))
    pFunc1 := (*Person).PrintInfoPointer
    pFunc1(&p) //0xc0420023e0, &{mike 109 18}

    pFunc2 := Person.PrintInfoValue
    pFunc2(p) //0xc042002460, {mike 109 18}
}

8.4 接口

8.4.1 概述

在Go語言中,接口(interface)是一個自定義類型笔时,接口類型具體描述了一系列方法的集合棍好。

接口類型是一種抽象的類型,它不會暴露出它所代表的對象的內(nèi)部值的結(jié)構(gòu)和這個對象支持的基礎(chǔ)操作的集合,它們只會展示出它們自己的方法借笙。因此接口類型不能將其實例化扒怖。

Go通過接口實現(xiàn)了鴨子類型(duck-typing):“當看到一只鳥走起來像鴨子、游泳起來像鴨子业稼、叫起來也像鴨子盗痒,那么這只鳥就可以被稱為鴨子”。我們并不關(guān)心對象是什么類型低散,到底是不是鴨子俯邓,只關(guān)心行為。

8.4.2 接口的使用

8.4.2.1 接口定義

type Humaner interface {
    SayHi()
}

接?命名習(xí)慣以 er 結(jié)尾
接口只有方法聲明熔号,沒有實現(xiàn)稽鞭,沒有數(shù)據(jù)字段
接口可以匿名嵌入其它接口,或嵌入到結(jié)構(gòu)中

8.4.2.2 接口實現(xiàn)

接口是用來定義行為的類型引镊。這些被定義的行為不由接口直接實現(xiàn)朦蕴,而是通過方法由用戶定義的類型實現(xiàn),一個實現(xiàn)了這些方法的具體類型是這個接口類型的實例弟头。

如果用戶定義的類型實現(xiàn)了某個接口類型聲明的一組方法吩抓,那么這個用戶定義的類型的值就可以賦給這個接口類型的值。這個賦值會把用戶定義的類型的值存入接口類型的值赴恨。

type Humaner interface {
    SayHi()
}

type Student struct { //學(xué)生
    name  string
    score float64
}

//Student實現(xiàn)SayHi()方法
func (s *Student) SayHi() {
    fmt.Printf("Student[%s, %f] say hi!!\n", s.name, s.score)
}

type Teacher struct { //老師
    name  string
    group string
}

//Teacher實現(xiàn)SayHi()方法
func (t *Teacher) SayHi() {
    fmt.Printf("Teacher[%s, %s] say hi!!\n", t.name, t.group)
}

type MyStr string

//MyStr實現(xiàn)SayHi()方法
func (str MyStr) SayHi() {
    fmt.Printf("MyStr[%s] say hi!!\n", str)
}

//普通函數(shù)疹娶,參數(shù)為Humaner類型的變量i
func WhoSayHi(i Humaner) {
    i.SayHi()
}

func main() {
    s := &Student{"mike", 88.88}
    t := &Teacher{"yoyo", "Go語言"}
    var tmp MyStr = "測試"

    s.SayHi()   //Student[mike, 88.880000] say hi!!
    t.SayHi()   //Teacher[yoyo, Go語言] say hi!!
    tmp.SayHi() //MyStr[測試] say hi!!

    //多態(tài),調(diào)用同一接口伦连,不同表現(xiàn)
    WhoSayHi(s)   //Student[mike, 88.880000] say hi!!
    WhoSayHi(t)   //Teacher[yoyo, Go語言] say hi!!
    WhoSayHi(tmp) //MyStr[測試] say hi!!

    x := make([]Humaner, 3)
    //這三個都是不同類型的元素雨饺,但是他們實現(xiàn)了interface同一個接口
    x[0], x[1], x[2] = s, t, tmp
    for _, value := range x {
        value.SayHi()
    }
    /*
        Student[mike, 88.880000] say hi!!
        Teacher[yoyo, Go語言] say hi!!
        MyStr[測試] say hi!!
    */
}

通過上面的代碼,你會發(fā)現(xiàn)接口就是一組抽象方法的集合惑淳,它必須由其他非接口類型實現(xiàn)沛膳,而不能自我實現(xiàn)。

8.4.3 接口組合

8.4.3.1 接口嵌入

如果一個interface1作為interface2的一個嵌入字段汛聚,那么interface2隱式的包含了interface1里面的方法。

type Humaner interface {
    SayHi()
}

type Personer interface {
    Humaner //這里想寫了SayHi()一樣
    Sing(lyrics string)
}

type Student struct { //學(xué)生
    name  string
    score float64
}

//Student實現(xiàn)SayHi()方法
func (s *Student) SayHi() {
    fmt.Printf("Student[%s, %f] say hi!!\n", s.name, s.score)
}

//Student實現(xiàn)Sing()方法
func (s *Student) Sing(lyrics string) {
    fmt.Printf("Student sing[%s]!!\n", lyrics)
}

func main() {
    s := &Student{"mike", 88.88}

    var i2 Personer
    i2 = s
    i2.SayHi()     //Student[mike, 88.880000] say hi!!
    i2.Sing("學(xué)生哥") //Student sing[學(xué)生哥]!!
}

8.4.3.2 接口轉(zhuǎn)換

超集接?對象可轉(zhuǎn)換為?集接?短荐,反之出錯:

type Humaner interface {
    SayHi()
}

type Personer interface {
    Humaner //這里像寫了SayHi()一樣
    Sing(lyrics string)
}

type Student struct { //學(xué)生
    name  string
    score float64
}

//Student實現(xiàn)SayHi()方法
func (s *Student) SayHi() {
    fmt.Printf("Student[%s, %f] say hi!!\n", s.name, s.score)
}

//Student實現(xiàn)Sing()方法
func (s *Student) Sing(lyrics string) {
    fmt.Printf("Student sing[%s]!!\n", lyrics)
}

func main() {
    //var i1 Humaner = &Student{"mike", 88.88}
    //var i2 Personer = i1 //err

    //Personer為超集倚舀,Humaner為子集
    var i1 Personer = &Student{"mike", 88.88}
    var i2 Humaner = i1
    i2.SayHi() //Student[mike, 88.880000] say hi!!
}

8.4.4 空接口

空接口(interface{})不包含任何的方法,正因為如此忍宋,所有的類型都實現(xiàn)了空接口痕貌,因此空接口可以存儲任意類型的數(shù)值。它有點類似于C語言的void *類型糠排。

var v1 interface{} = 1     // 將int類型賦值給interface{}
var v2 interface{} = "abc" // 將string類型賦值給interface{}
var v3 interface{} = &v2   // 將*interface{}類型賦值給interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}

當函數(shù)可以接受任意的對象實例時舵稠,我們會將其聲明為interface{},最典型的例子是標準庫fmt中PrintXXX系列的函數(shù),例如:

    func Printf(fmt string, args ...interface{})
    func Println(args ...interface{})

8.4.5 類型查詢

我們知道interface的變量里面可以存儲任意類型的數(shù)值(該類型實現(xiàn)了interface)哺徊。那么我們怎么反向知道這個變量里面實際保存了的是哪個類型的對象呢室琢?目前常用的有兩種方法:
comma-ok斷言
switch測試

8.4.5.1 comma-ok斷言

Go語言里面有一個語法,可以直接判斷是否是該類型的變量: value, ok = element.(T)落追,這里value就是變量的值盈滴,ok是一個bool類型,element是interface變量轿钠,T是斷言的類型巢钓。

如果element里面確實存儲了T類型的數(shù)值,那么ok返回true疗垛,否則返回false症汹。

示例代碼:

type Element interface{}

type Person struct {
    name string
    age  int
}

func main() {
    list := make([]Element, 3)
    list[0] = 1       // an int
    list[1] = "Hello" // a string
    list[2] = Person{"mike", 18}

    for index, element := range list {
        if value, ok := element.(int); ok {
            fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
        } else if value, ok := element.(string); ok {
            fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
        } else if value, ok := element.(Person); ok {
            fmt.Printf("list[%d] is a Person and its value is [%s, %d]\n", index, value.name, value.age)
        } else {
            fmt.Printf("list[%d] is of a different type\n", index)
        }
    }

    /*  打印結(jié)果:
    list[0] is an int and its value is 1
    list[1] is a string and its value is Hello
    list[2] is a Person and its value is [mike, 18]
    */
}

8.4.5.2 switch測試
type Element interface{}

type Person struct {
    name string
    age  int
}

func main() {
    list := make([]Element, 3)
    list[0] = 1       //an int
    list[1] = "Hello" //a string
    list[2] = Person{"mike", 18}

    for index, element := range list {
        switch value := element.(type) {
        case int:
            fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
        case string:
            fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
        case Person:
            fmt.Printf("list[%d] is a Person and its value is [%s, %d]\n", index, value.name, value.age)
        default:
            fmt.Println("list[%d] is of a different type", index)
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贷腕,隨后出現(xiàn)的幾起案子背镇,更是在濱河造成了極大的恐慌,老刑警劉巖花履,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芽世,死亡現(xiàn)場離奇詭異,居然都是意外死亡诡壁,警方通過查閱死者的電腦和手機济瓢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妹卿,“玉大人旺矾,你說我怎么就攤上這事《峥耍” “怎么了箕宙?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铺纽。 經(jīng)常有香客問我柬帕,道長,這世上最難降的妖魔是什么狡门? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任陷寝,我火速辦了婚禮,結(jié)果婚禮上其馏,老公的妹妹穿的比我還像新娘凤跑。我一直安慰自己,他們只是感情好叛复,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布仔引。 她就那樣靜靜地躺著扔仓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咖耘。 梳的紋絲不亂的頭發(fā)上翘簇,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音鲤看,去河邊找鬼缘揪。 笑死,一個胖子當著我的面吹牛义桂,可吹牛的內(nèi)容都是我干的找筝。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼慷吊,長吁一口氣:“原來是場噩夢啊……” “哼袖裕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溉瓶,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤急鳄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后堰酿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疾宏,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年触创,在試婚紗的時候發(fā)現(xiàn)自己被綠了坎藐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡哼绑,死狀恐怖岩馍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抖韩,我是刑警寧澤蛀恩,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站茂浮,受9級特大地震影響双谆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜席揽,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一佃乘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驹尼,春花似錦、人聲如沸庞呕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至地啰,卻和暖如春愁拭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亏吝。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工岭埠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔚鸥。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓惜论,卻偏偏與公主長得像,于是被迫代替她去往敵國和親止喷。 傳聞我的和親對象是個殘疾皇子馆类,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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