Go語言結(jié)構(gòu)類型詳解

公眾號 ”陸貴成“ 踩麦,專注精進(jìn)Go開發(fā)

Go允許用戶自定義類型,當(dāng)你需要用代碼抽象描述一個事物或者對象的時候囚聚,可以聲明一個 struct 類型來進(jìn)行描述靖榕。

當(dāng)然,Go語言中顽铸,用戶還可以基于已有的類型來定義其他類型茁计。

簡單來說,Go語言中用戶可以有兩種方法定義類型谓松,第一種是使用 struct 關(guān)鍵字來創(chuàng)造一個結(jié)構(gòu)類型星压;第二種是基于已有的類型,將其作為新類型的類型說明鬼譬。

01. 自定義類型的基本使用

基于已有的類型的這種方式比較簡單娜膘,但需要注意的是,雖然是基于已有類型來定義新類型优质,但是基礎(chǔ)類型和新類型是完全不同的兩種類型竣贪,不能相互賦值,因?yàn)镚o語言中巩螃,編譯器不會對不同類型的值做隱式轉(zhuǎn)換演怎。

當(dāng)需要使用一個比較明確的名字類描述一種類型時,使用這種自定義類型就比較合適避乏,比如定義一個表示年齡的類型可以基于整形來定義一個 Age 類型爷耀,特指年齡類型。

下面是基于已有類型的方式定義類型的示例

// 基于 int64 聲明一個 Duration 類型
// int 是 Duration 的基本類型
// 但是他們是兩個完全不同的類型拍皮,在Go中是不能相互賦值的
type Duration int
?
// 聲明一個 Duration 類型的變量 d
var d Duration
// 聲明并初始化int類型的變量i 為 50
i := 50
// 嘗試賦值會報錯
d = i // Cannot use 'i' (type int) as type Duration

使用關(guān)鍵字 struct 來聲明一個結(jié)構(gòu)類型時歹叮,要求字段是固定并且唯一的,并且字段的類型也是已知的铆帽,但是字段類型可以是內(nèi)置類型(比如 string, bool, int 等等)咆耿,也可以是用戶自定義的類型(比如,本文中介紹的 struct 類型)爹橱。

聲明struct 結(jié)構(gòu)體的公式:type 結(jié)構(gòu)體名稱 struct {} 票灰。

在任何時候,創(chuàng)建一個變量并初始化其零值時,我們習(xí)慣是使用關(guān)鍵字 var屑迂,這種用法是為了更明確的表示變量被設(shè)置為零值。

而如果是變量被初始化為非零值時冯键,則使用短變量操作符:=和結(jié)構(gòu)字面量 結(jié)構(gòu)類型{ 字段: 字段值, }或者 結(jié)構(gòu)類型{ 字段1值, 字段2值 }來創(chuàng)建變量惹盼。

兩種字面量初始化方式的差異與限制:

結(jié)構(gòu)類型{ 字段1值, 字段2值 }這種初始化方式時:

  1. 在最后一個字段值的結(jié)尾可以不用加逗號,

  2. 必須嚴(yán)格按照聲明時的字段順序來進(jìn)行初始化,不然會得不到預(yù)期的結(jié)果惫确;如果字段類型不一致手报,還會導(dǎo)致初始化失敗

  3. 必須要初始化所有的字段,不然會報錯 Too few values

結(jié)構(gòu)類型{ 字段: 字段值, }這種初始化方式時:

  1. 每一個字段值的結(jié)尾必須要加一個逗號,

  2. 初始化時改化,不要考慮字段聲明的順序

  3. 允許只初始化部分字段

package main
  import "log"
  
  // 聲明無狀態(tài)的空結(jié)構(gòu)體 animal
  type animal struct {}
  
  // 聲明一個結(jié)構(gòu)體 cat
  // 內(nèi)部有有 name, age 兩個字段
  // 字段 name 類型為 string類型
  // 字段 age 類型為 int 類型
  type cat struct {
    name string
    age int
  }
  
func main() {
  // 初始化1
  var c1 cat
  log.Println(c1) // { 0}
?
  // 初始化2
  // c2 := cat{"kitten"} // 報錯:Too few values
  c2 := cat{"kitten", 1}
  log.Println(c2) // {kitten 1}
?
  // 初始化3
  c3 := cat{age: 2}
  log.Println(c3, c3.age) //  { 2} 2
  
  // 變量字段賦值
  c3.name = "kk"
?
  // 字段訪問
  // 變量.字段名稱
  log.Println(c3.name) // kk
}

以上是 struct 結(jié)構(gòu)類型的基本使用掩蛤,但是在項目開發(fā)中會遇到其他的用法,比如解析 json 或者 xml 文件到結(jié)構(gòu)體類型變量中陈肛。

// 解析 json 的示例
// 數(shù)據(jù)文件
// data.json
[
  {
    "site" : "npr",
    "link" : "http://www.npr.org/rss/rss.php?id=1001",
    "type" : "rss"
  },
  {
?    "site" : "npr",
    "link" : "http://www.npr.org/rss/rss.php?id=1008",
    "type" : "rss"
  },
  {
    "site" : "npr",
    "link" : "http://www.npr.org/rss/rss.php?id=1006",
    "type" : "rss"
  }
]
?
// main.go
package main
?
import (
  "encoding/json"
  "log"
  "os"
)
?
type Feed struct {
  Site string `json:"site"`
  Link string `json:"link"`
  Type string `json:"type"`
}
?
// 解析 JSON 數(shù)據(jù)
func ParseJSON(path string) ([]*Feed, error) {
  file, err := os.Open(path)
  if err != nil {
    return nil, err
  }
?
  // 注意:打開文件之后揍鸟,記得要關(guān)閉文件
  defer file.Close()
?
  // 注意:文件讀取后,需要結(jié)構(gòu)體來解析json數(shù)據(jù)
  var files []*Feed
  json.NewDecoder(file).Decode(&files)
  return files, nil
}
?
func main() {
  // 讀取并解析 json 數(shù)據(jù)
  var path = "./data.json"
  feeds, err := ParseJSON(path)
  if err != nil {
    log.Println("error: ", err)
  }
  for i, val := range feeds {
    log.Printf("%d - site:%s, link:%s, type:%s", i, val.Site, val.Link, val.Type)
  }
}
// 解析 xml 數(shù)據(jù)到結(jié)構(gòu)體中示例
// data.xml
<?xml version="1.0" encoding="utf-8" ?>
<content>
    <item>
        <site>npr</site>
        <link>http://www.npr.org/rss/rss.php?id=1001</link>
        <type>rss</type>
    </item>
    <item>
        <site>npr</site>
        <link>http://www.npr.org/rss/rss.php?id=1002</link>
        <type>rss</type>
    </item>
    <item>
        <site>npr</site>
        <link>http://www.npr.org/rss/rss.php?id=1003</link>
        <type>rss</type>
    </item>
</content>
?
// main.go
package main
?
import (
  "encoding/xml"
  "io/ioutil"
  "log"
  "os"
)
?
type Content struct {
  XMLName xml.Name `xml:"content"` // 指定xml中的名稱
  Item []item `xml:"item"`
}
type item struct {
  XMLName xml.Name `xml:"item"` // 指定xml中的名稱
  Site string `xml:"site"`
  Link string `xml:"link"`
  Type string `xml:"type"`
}
?
// 解析 XML 數(shù)據(jù)
func ParseXML(path string) (*Content, error) {
  // 讀取 xml
  data, err := ioutil.ReadFile(path)
  if err != nil {
    return nil, err
  }
?
  var con Content
  // 解析 xml
  xml.Unmarshal(data, &con)
  return &con, nil
}
?
func main() {
  // 讀取并解析 xml 數(shù)據(jù)
  var xmlpath = "./data.xml"
  content, err := ParseXML(xmlpath)
  if err != nil {
    log.Println("error: ", err)
  }
  for i, val := range content.Item {
    log.Printf("%d - site:%s, link:%s, type:%s", i, val.Site, val.Link, val.Type)
  }
}

02. 公開或未公開的標(biāo)識符

在Go語言中句旱,聲明類型阳藻、函數(shù)、方法谈撒、變量等標(biāo)識符時腥泥,使用大小寫字母開頭來區(qū)分該標(biāo)識符是否公開(即是否能在包外訪問)。

大寫字母開頭表示公開啃匿,小寫字母開頭表示非公開蛔外。所以如果某個結(jié)構(gòu)類型以及結(jié)構(gòu)類型的字段,函數(shù),方法,變量等標(biāo)識符止潘,想要被外部訪問到囱井,那必須以大寫字母開頭。

// user 包
package user
?
// 基于 int 類型聲明一個 duration 類型
// 未公開的類型(以小寫字母開頭)
// 包外部盹靴,不能直接訪問
type duration int
?
// 公開的類型(以大寫字母開頭)
// 包外部能直接訪問
type Duration int
?
// 未公開的結(jié)構(gòu)類型 user
type user struct {
  name string
}
?
// 公開的結(jié)構(gòu)類型 User
type User struct {
  Name string
  phone string
  address
}
?
// 未公開的 address 類型
// 包含公開的字段 City
type address struct {
  City string
  position position
}
?
type position struct {
  Longitude string
  Latitude string
}
?
// 通過工廠函數(shù),返回未公開的變量類型
func New(num int) duration {
  return duration(num)
}

// main 包
package main
?
import (
  "go-demo/user"
  "log"
)
?
func main() {
  // ------
?
  // 在 main 包中,試圖使用 user 包中的為公開的 duration 類型
  //var d1 user.duration = 10 // 報錯:Unexported type 'duration' usage
?
  // ------
?
  // 在 main 包中崖技,訪問一個 user 包中公開的 Duration 類型
  var d2 user.Duration = 10
  log.Println(d2) // 結(jié)果:10
?
  // ------
?
  // 還可以以工廠函數(shù)的方式使用,user 包中未公開的類型
  d3 := user.New(100)
  log.Printf("type: %T, value:%d", d3, d3) // 結(jié)果:type: user.duration, value:100
?
  // ------
?
  // main包中嘗試訪問 user 包中未公開的結(jié)構(gòu)類型 user
  //var u user.user // 報錯:Unexported type 'user' usage
?
  // ------
?
  // main包中嘗試訪問 user 包中公開的結(jié)構(gòu)類型 User
  var u user.User
  log.Printf("%#v", u) // 結(jié)果:user.User{name:""}
?
  // 訪問公開 User 類型的未公開的字段 phone
  //log.Println(u.phone) // 報錯:Unexported field 'phone' usage
?
  // 初始化未公開的字段 phone
  //u2 := user.User{phone: "176888888888"} // 報錯:Unexported field 'phone' usage in struct literal
?
  // 訪問公開 User 類型的公開的字段 Name
  // 給字段賦值
  //u.Name = "Jack"
  //log.Println(u.Name) // 結(jié)果:Jack
?
  // 初始化公開字段
  u3 := user.User{
    Name: "Jack",
  }
  log.Println(u3.Name) // 結(jié)果:Jack
?
  // ------
?
  // main 包中初始化 user 包中公開的 User 類型中嵌套的未公開的 address 類型
  // 報錯:Unexported field 'address' usage in struct literal
  //u4 := user.User{
  //  address: address{
  //    City: "Beijing",
  //  },
  //}
?
?
  var u5 user.User
  // 嵌套的結(jié)構(gòu)類型會提升到上級結(jié)構(gòu)中
  u5.City = "Beijing"
  log.Println(u5.City) // Beijing
?
  // 嘗試訪問子孫級別的嵌套結(jié)構(gòu)的公開的字段
  // 無法訪問
  //u5.Longitude = "xx" //報錯:u5.Longitude undefined (type user.User has no field or method Longitude)
}
?

03. 給自定義類型增加方法

在Go語言中钟哥,編譯器只允許為命名的用戶定義的類型聲明方法迎献。方法跟函數(shù)類似,只是方法不會單獨(dú)存在腻贰,一般是綁定到某個結(jié)構(gòu)類型中吁恍,給類型增加方法的方式很簡單,就是在方法名和 func 之間增加一個參數(shù)即可, 這個參數(shù)稱為方法的接收者。

type User struct {
  Name string
}
?
// 給 User 類型增加方法 Read
func (u User) Read() {
  log.Println(u.Name, "is Reading...")
}
?
// User 類型變量使用 Read 方法
func main() {
  u := User{
    Name: "Jack",
  }
  u.Read() // 結(jié)果 Jack is Reading...
}

方法的接收者冀瓦,可以是值接收者伴奥,也可以是指針接收者。

而應(yīng)該使用值接收者還是指針接收者翼闽,那要看給這個類型增加或刪除某個值時拾徙,是創(chuàng)建一個新值,還是要更改當(dāng)前值感局?如果是要創(chuàng)建一個新值尼啡,該類型的方法就使用值接收者;如果是要修改當(dāng)前值询微,就使用指針接收者崖瞭。

?package main
?
import "log"
?
// 基于基本類型創(chuàng)建類型
type Age int
?
// 值接收者
func (age Age) ChangeAge() {
  age = 18
}
// 指針接收者
func (age *Age) ChangeAgeByPointer() {
  *age = 18
}
?
// 基于引用類型創(chuàng)建類型
type IP []byte
?
// 值接收者
func (ip IP) ChangeIP() {
  ip = []byte("456")
}
?
// 指針接收者
func (ip *IP) ChangeIPByPointer() {
  *ip = []byte("456")
}
?
type Pet struct {
  Name string
  Hobby []string
}
?
// 值接收者
func (pet Pet) ChangePetValue(name string, hobby []string) {
  pet.Name = name
  pet.Hobby = hobby
}
?
// 指針接收者
func (pet *Pet) ChangePetValueByPointer(name string, hobby []string) {
  pet.Name = name
  pet.Hobby = hobby
}
?
func main() {
  // -----基于基本類型來定義類型的示例-----
  // 值接收者,不會改變原來的值
  var age Age = 38
  log.Println("前age=", age) // 前age= 38
  // 值調(diào)用方法
  age.ChangeAge()
  // 指針調(diào)用方法
  //(&age).ChangeAge()
?
  log.Println("后age=", age) // 后age= 38
?
  // 指針接收者撑毛,會改變原來的值
  var age2 Age = 38
  log.Println("前age2=", age2) // 前age= 38
  // 值調(diào)用方法
  age2.ChangeAgeByPointer()
  // 指針調(diào)用方法
  //(&age2).ChangeAgeByPointer()
?
  log.Println("后age2=", age2) // 后age= 18
?
?
  // -----基于引用類型來定義類型的示例-----
  // 值接收者书聚,不會改變原來的值
  var ip IP = []byte("123")
  log.Printf("前ip=%s", ip) // 前ip=123
  // 值調(diào)用方法
  ip.ChangeIP()
  // 指針調(diào)用方法
  //(&ip).ChangeIP()
  log.Printf("后ip=%s", ip) // 后ip=123
?
  // 指針接收者,會改變原來的值
  var ip2 IP = []byte("123")
  log.Printf("前ip2=%s", ip2) // 前ip2=123
  // 值調(diào)用方法
  ip2.ChangeIPByPointer()
  // 指針調(diào)用方法
  //(&ip2).ChangeIPByPointer()
  log.Printf("后ip2=%s", ip2) // 后ip2=456
?
?
  // ----- struct 類型 -----
  // 值接收者代态,不會改變原來的值
  cat := Pet{
    Name: "kk",
    Hobby: []string{"cookies", "fishes"},
  }
  log.Printf("前:%#v", cat) // 前:method.Pet{Name:"kk", Hobby:[]string{"cookies", "fishes"}}
  // 值調(diào)用方法
  cat.ChangePetValue("kitten", []string{"meat"})
  // 指針調(diào)用方法
  //(&cat).ChangePetValue("kitten", []string{"meat"})
  log.Printf("后:%#v", cat) // 后:method.Pet{Name:"kk", Hobby:[]string{"cookies", "fishes"}}
?
  // 指針接收者寺惫,會改變原來的值
  log.Printf("指針前:%#v", cat) // 指針前:method.Pet{Name:"kk", Hobby:[]string{"cookies", "fishes"}}
  // 值調(diào)用方法
  cat.ChangePetValueByPointer("kitten", []string{"meat"}) 
  // 指針調(diào)用方法
  //(&cat).ChangePetValueByPointer("kitten", []string{"meat"})
  log.Printf("指針后:%#v", cat) // 指針后:method.Pet{Name:"kitten", Hobby:[]string{"meat"}}
}

04. 嵌入類型

Go語言通過類型嵌套的方式來復(fù)用代碼,當(dāng)多個結(jié)構(gòu)類型相互嵌套時蹦疑,外部類型會復(fù)用內(nèi)部類型的代碼西雀。

由于內(nèi)部類型的標(biāo)識符會提升到外部類型中,所以內(nèi)部類型實(shí)現(xiàn)的字段歉摧,方法和接口在外部類型中也能直接訪問到艇肴。

當(dāng)外部類型需要實(shí)現(xiàn)一個和內(nèi)部類型一樣的方法或接口時,只需要給外部類型重新綁定方法或?qū)崿F(xiàn)接口即可叁温。

package main
?
import "log"
?
// user 類型
type user struct {
  name string
  phone string
}
?
// 給 user 實(shí)現(xiàn) Call 方法
func (u *user) Call() {
  log.Printf("Call user %s<%s>", u.name, u.phone)
}
?
// Admin 類型 (外部類型)
// 嵌套 user (內(nèi)部類型)
type Admin struct {
  user
  level string
}
?
// 重新實(shí)現(xiàn) Admin 類型的 Call 方法
func (ad *Admin) Call() {
  log.Printf("Call admin %s<%s>", ad.name, ad.phone)
}
?
// 定義一個接口 notifier,
// 接口需要實(shí)現(xiàn)一個 notify 方法
type notifier interface {
  notify()
}
?
// 給 user 實(shí)現(xiàn) notify 方法
func (u *user) notify() {
  log.Printf("Sending a message to user %s<%s>", u.name, u.phone)
}
?
// 定義一個函數(shù) sendNotification
// 函數(shù)接收一個實(shí)現(xiàn)了 notifier 接口的值
// 然后調(diào)用參數(shù)的 notify 方法
func sendNotification(n notifier) {
  n.notify()
}
?
// 給 Admin 實(shí)現(xiàn) notify 方法
func (ad *Admin) notify() {
  log.Printf("Sending a message to ADMIN %s<%s>", ad.name, ad.phone)
}
?
func main() {
  // 聲明并初始化 Admin 類型的變量 ad
  ad := Admin{
    user: user{
      name: "Jack",
      phone: "17688888888",
    },
    level: "super",
  }
  // ad 調(diào)用 user 內(nèi)部的 Call 方法
  ad.user.Call() // Call user Jack<17688888888>
?
  // 由于內(nèi)部類型的標(biāo)識符提升再悼,所以外部類型值 ad 也可以直接調(diào)用其內(nèi)部類型的標(biāo)識符(字段,方法膝但,接口等)
  ad.Call() // Call user Jack<17688888888>
  log.Println(ad.name, ad.phone) // Jack 17688888888
?
  // ad 重新實(shí)現(xiàn)一個和內(nèi)部類型 user 一樣的 Call 方法
  // 覆蓋內(nèi)部類型 user 提升的 Call 方法
  ad.Call() // Call admin Jack<17688888888>
?
  // user 內(nèi)部的 Call 方法沒有變化
  ad.user.Call() // Call user Jack<17688888888>
?
?
  // 外部類型和內(nèi)部類型調(diào)用接口方法
  sendNotification(&ad) // Sending a message to user Jack<17688888888>
  ad.notify() // Sending a message to user Jack<17688888888>
  ad.user.notify() // Sending a message to user Jack<17688888888>
?
  // 外部類型重新實(shí)現(xiàn)接口方法后
  sendNotification(&ad) // Sending a message to ADMIN Jack<17688888888>
  ad.notify() // Sending a message to ADMIN Jack<17688888888>
  ad.user.notify() // Sending a message to user Jack<17688888888>
}

05.類型實(shí)現(xiàn)接口

Go語言中冲九,接口是用來定義行為的類型,這些被定義的行為不由接口直接實(shí)現(xiàn)跟束,而是通過方法由用戶定義的類型實(shí)現(xiàn)莺奸。

如果用戶定義的類型實(shí)現(xiàn)了某個接口里的一組方法,那么用戶定義的這個類型值冀宴,就可以賦值給該接口值灭贷,此時用戶定義的類型稱為實(shí)體類型。

而用戶定義的類型想要實(shí)現(xiàn)一個接口略贮,需要遵循一些規(guī)則甚疟,這些規(guī)則使用方法集來進(jìn)行定義仗岖。

從類型實(shí)現(xiàn)方法的接收者角度來看,可以描述為以下表格览妖。

方法接收者 類型值
(t T) T and *T
(t *T) *T

表示當(dāng)類型的方法為指針接收者時轧拄,只有類型值的指針,才能實(shí)現(xiàn)接口讽膏。

如果類型的方法為值接收者紧帕,那么類型值還是類型值的指針都能夠?qū)崿F(xiàn)對應(yīng)的接口。

package main
?
import "log"
?
// 定義一個接口 notifier
// 要實(shí)現(xiàn) notifier 接口必須實(shí)現(xiàn) notify 方法
type notifier interface {
  notify()
}
?
type user struct {
  name string
  phone string
}
?
// 指針接收者
func (u *user) notify() {
  log.Println("Send user a text")
}
?
type Admin struct {
  user
  level string
}
?
// 值接收者
func (ad Admin) notify() {
  log.Println("Send admin a message")
}
// 多態(tài)函數(shù)
func sendNotification(n notifier) {
  n.notify()
}
?
func main() {
  // ---指針接收者方法的類型實(shí)現(xiàn)接口示例---
  u := user{
    name: "Jack",
    phone: "17688888888",
  }
  // 嘗試將類型值實(shí)現(xiàn)接口 notifier
  // 因?yàn)轭愋偷姆椒ㄊ侵羔樈邮照?  // 使用類型值實(shí)現(xiàn)接口時桅打,會編譯不通過
  //var n notifier = u // Cannot use 'u' (type user) as type notifier Type does not implement 'notifier' as 'notify' method has a pointer receiver
?
  // 使用類型值得指針,可以正常實(shí)現(xiàn)接口
  var n notifier = &u
  n.notify() // Send user a text
?
?
  // ---值接收者方法的類型實(shí)現(xiàn)接口示例---
?
  // 實(shí)現(xiàn)值接收者方法的類型實(shí)現(xiàn)接口
  ad := Admin{
    user: user{"Jack", "17688888888"},
    level: "super",
  }
  // 使用類型值實(shí)現(xiàn)接口愈案,成功
  var n2 notifier = ad
  n2.notify() // Send admin a message
?
  // 使用類型值的指針實(shí)現(xiàn)接口, 成功
  var n3 notifier = &ad
  n3.notify() // Send admin a message
  
  
  // -------多態(tài)示例--------
?
  // 接口值多態(tài)
  // 因?yàn)?Admin 和 user 兩個類型都實(shí)現(xiàn)了接口
  // 而 sendNotification 函數(shù)接收一個 notifier 接口值
  // 然后調(diào)用接口值對應(yīng)的 notify 方法
  // 從而實(shí)現(xiàn)了接口值的多態(tài)
  sendNotification(n) // Send user a text
  sendNotification(n3) // Send admin a message
}

本文為原創(chuàng)文章挺尾,轉(zhuǎn)發(fā)請注明出處。

關(guān)注公眾號 ”陸貴成“站绪,學(xué)習(xí)更多Go精彩文章遭铺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恢准,隨后出現(xiàn)的幾起案子魂挂,更是在濱河造成了極大的恐慌,老刑警劉巖馁筐,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂召,死亡現(xiàn)場離奇詭異,居然都是意外死亡敏沉,警方通過查閱死者的電腦和手機(jī)果正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盟迟,“玉大人秋泳,你說我怎么就攤上這事≡懿ぃ” “怎么了迫皱?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辖众。 經(jīng)常有香客問我卓起,道長,這世上最難降的妖魔是什么赵辕? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任既绩,我火速辦了婚禮,結(jié)果婚禮上还惠,老公的妹妹穿的比我還像新娘饲握。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布救欧。 她就那樣靜靜地躺著衰粹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笆怠。 梳的紋絲不亂的頭發(fā)上铝耻,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音蹬刷,去河邊找鬼瓢捉。 笑死,一個胖子當(dāng)著我的面吹牛办成,可吹牛的內(nèi)容都是我干的泡态。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼迂卢,長吁一口氣:“原來是場噩夢啊……” “哼某弦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起而克,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤靶壮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后员萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腾降,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年充活,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜂莉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡混卵,死狀恐怖映穗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幕随,我是刑警寧澤蚁滋,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站赘淮,受9級特大地震影響辕录,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梢卸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一走诞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛤高,春花似錦蚣旱、人聲如沸碑幅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沟涨。三九已至,卻和暖如春异吻,著一層夾襖步出監(jiān)牢的瞬間裹赴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工诀浪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棋返,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓雷猪,卻偏偏與公主長得像懊昨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子春宣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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