Go語言基礎(chǔ)(二)—— 基本常用語法

前言:
本專題用于記錄自己(647)在Go語言方向的學(xué)習(xí)和積累刚陡。
系列內(nèi)容比較偏基礎(chǔ)啤斗,推薦給想要入門Go語言開發(fā)者們閱讀焚鲜。

目錄如下:
Go語言基礎(chǔ)(一)—— 簡介曲尸、環(huán)境配置、HelloWorld
Go語言基礎(chǔ)(二)—— 基本常用語法
Go語言基礎(chǔ)(三)—— 面向?qū)ο缶幊?/a>
Go語言基礎(chǔ)(四)—— 優(yōu)質(zhì)的容錯處理
Go語言基礎(chǔ)(五)—— 并發(fā)編程
Go語言基礎(chǔ)(六)—— 測試比肄、反射快耿、Unsafe
Go語言基礎(chǔ)(七)—— 架構(gòu) & 常見任務(wù)
Go語言基礎(chǔ)(八)—— 性能調(diào)優(yōu)


本篇將介紹如下內(nèi)容:
1.如何編寫一個Go測試程序?
2.變量薪前、常量的定義
3.基本數(shù)據(jù)類型
4.指針類型
5.運算符
6.條件與循環(huán)
7.數(shù)組與切片
8.Map
9.字符串
10.函數(shù)
(注:可根據(jù)數(shù)字快速定位本篇內(nèi)容)


為了接下來更方便的測試我們的Go代碼(Go服務(wù))润努,
首先关斜,介紹一下Go語言中如何測試我們的程序示括。

一、起步:如何編寫一個測試程序痢畜?

要求:

  1. 源碼文件以_test結(jié)尾:
    xxx_test.go

  2. 測試方法名以Test開頭:
    func TestXXX(t *testing.T){...}

實際步驟:

  • 創(chuàng)建一個first_test.go文件垛膝。

  • 編寫如下代碼:

package try_test

import "testing"

func TestFirstTry(t *testing.T) {
    t.Log("My first try!")
}

在終端下運行:

go test first_test.go -v

Demo:動手實現(xiàn)一個斐波那切(Fibonacci)數(shù)列

1,1丁稀,2吼拥,3,5线衫,8凿可,13,...

  • 創(chuàng)建一個fibonacci_test.go文件授账。

  • 編寫如下代碼:

package fibonacci

import (
    "testing"
)

func TestFibList(t *testing.T) {
    // var a int = 1
    // var b int = 1

    // var (
    //  a int = 1
    //  b int = 1
    // )

    a := 1
    b := 1

    for i := 0; i < 5; i++ {
        t.Log(" ", b)
        tmp := a
        a = b
        b = tmp + a
    }
}
  • 在終端下運行:
go test fibonacci_test.go -v

二枯跑、變量、常量的定義

1.變量

變量的定義白热,有3種方式:

  • 第一種敛助,常規(guī)逐一聲明:
    var a int = 1
    var b int = 1
  • 第二種:統(tǒng)一聲明:
    var (
      a int = 1
      b int = 1
    )
  • 第三種:快速聲明,編譯器會根據(jù)所附的值推斷出該變量的類型屋确。
    a := 1
    b := 1

2.常量

  • 常規(guī)賦值:
 const abc = 2
  • 快速設(shè)置連續(xù)常量值:
// 連續(xù)位常量賦值
const (
    Monday = iota + 1
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)
  • 快速設(shè)置連續(xù)比特位常量值:
// 比特位常量賦值
const (
    Readabele = 1 << iota
    Writeable
    Executable
)

三纳击、基本數(shù)據(jù)類型

類型 語法
布爾型 bool
字符型 string
整型 int、int8攻臀、int16焕数、int32、int64
無負(fù)號整型 uint刨啸、uint8百匆、uint16、uint32呜投、uint64加匈、uintptr
浮點型 float32存璃、float64
字符型 byte(相當(dāng)于uint8)
Unicode或utf-8編碼 rune(相當(dāng)于int32)
復(fù)數(shù)型 complex64、complex128

注意:Go語言不支持“隱式類型轉(zhuǎn)換”雕拼,只支持“顯式類型轉(zhuǎn)換”纵东。
(甚至連“別名類型”“原有類型”之間也不支持隱式類型轉(zhuǎn)換。)

舉例:

    var a int32 = 1
    var b int64

    b = a        // 錯誤:隱式類型轉(zhuǎn)換啥寇,會報編譯錯誤錯誤偎球。
    b = int64(a) // 正確:顯式類型轉(zhuǎn)換,成功辑甜。

常用典型的預(yù)定義值:

預(yù)定義 語法
最大Int64 math.MaxInt64
最小Int64 math.MinInt64
最小Int32 math.MaxInt32
最小Int32 math.MinInt32
最大float64 math.MaxFloat64
最大float32 math.MaxFloat32
... ...

四衰絮、指針類型

與其他編程語言的差異:

  • 不支持指針運算。

  • string是值類型磷醋,其默認(rèn)的初始化值為空字符串猫牡,而不是nil

舉例:

func TestPoint(t *testing.T) {
    a := 1
    aPoint := &a
    // aPoint = aPoint + 1 // 錯誤:Go不支持指針運算邓线。
    t.Log(a, aPoint)
    t.Logf("%T %T", a, aPoint)
}

func TestString(t *testing.T) {
    var s string
    t.Log("字符串:" + s + "?")
    t.Log(len(s))

    if s == "" { // 判斷字符串有無初始化不能判nil淌友,因為string類型的初始化默認(rèn)是空字符串
        t.Log("s并未初始化")
    }
}

五、運算符

1.算數(shù)運算符:

運算符 描述
+
-
*
/
% 取余
a++ 后置自增
a-- 后置自減

注:Go語言中沒有前置的自增(++)和自減(--)骇陈。

2.比較運算符:

運算符 描述
== 判斷值是否 “相等”
!= 判斷值是否 “不相等”
> 判斷是否 “大于”
< 判斷是否 “小于”
>= 判斷是否 “大于等于”
<= 判斷是否 “小于等于”

注:兩個數(shù)組之間的 == 比較的條件震庭? (還是值比較,并非引用比較)
1.兩個數(shù)組擁有 “相同的元素個數(shù)” 你雌。
2.兩個數(shù)組中的 “每個元素的值都相等” 器联,才會返回true

我們寫個小demo婿崭,測試一下:

    a := [...]int{1, 2, 3, 4}
    b := [...]int{1, 3, 4, 5}
    c := [...]int{1, 2, 3, 4}
    d := [...]int{1, 2, 3, 4, 5}

    t.Log(a == b) // false
    t.Log(a == c) // true

    // t.Log(a == d) // 編譯報錯拨拓,數(shù)組元素不一致
    t.Log(d)

3.邏輯運算符:

和別的語言沒太大差別,簡單提一下逛球。

運算符 描述
&& AND(與)運算符千元,同truetrue,否則false颤绕。
|| OR(或)運算符幸海,同falsefalse,否則true奥务。
! NOT(非)運算符物独,取反,truefalse氯葬,falsetrue挡篓。

4.位運算符:(新增&^按位清零運算符)

運算符 描述
& 二進(jìn)制“與”運算。
| 二進(jìn)制“或”運算。
^ 二進(jìn)制“異或”運算官研。
<< 二進(jìn)制“左移”運算秽澳。
>> 二進(jìn)制“右移”運算。
&^ 將二進(jìn)制 “按位清零” 戏羽。將右邊所有為1的位數(shù)全置為0担神。(對左邊數(shù)進(jìn)行操作)

注意:多了一個&^,按位清零運算符始花。

舉個栗子:

// 連續(xù)位常量賦值
const (
    Monday = iota + 1
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)

// 測試按位清零
func TestBitClear(t *testing.T) {
    a := 5 // 0101
    t.Log("按位清零前:", a) // 0101

    a = a &^ Wednesday // 5 &^ 3
    t.Log("按位清零后:", a) // 0100
}

六妄讯、條件與循環(huán)

1.條件:if

與別的編程語言的區(qū)別:

  1. 條件必須是bool類型
  2. 支持變量賦值

類似這樣:

    if var declaration; condition {
        //...
    }

舉個簡單例子:

    if a := 647; a == 647 {
        t.Log(a)
    }

如果寫了個請求,類似就成了這樣:

    if v, err := someFunc(); err == nil {
        // 無error酷宵,成功亥贸!do something!
    } else {
        // 有error浇垦,失斂恢谩!do something溜族!
    }

2.條件:switch

switch與其他主流編程語言有些區(qū)別讹俊,主要是變得更方便垦沉、更快捷了煌抒。

  1. 默認(rèn)break,不需要主動寫break厕倍。(如果想要貫穿寡壮,才用fallthrough關(guān)鍵字,這點與swift很像讹弯。注意:但我測試結(jié)果走fallthrough并不會去判斷下一個case條件况既,而是直接執(zhí)行下一個case里的代碼)
  2. 條件表達(dá)式不限制“常量”或“整數(shù)”。
  3. 單個case支持多個結(jié)果選項组民,用逗號隔開棒仍。
  4. 可以不設(shè)定switch之后的條件表達(dá)式,這樣與多個if臭胜、else邏輯相同莫其。

舉個例子:

func TestSwitchCondition(t *testing.T) {
    for i := 0; i < 5; i++ {
        switch i {
        case 0, 2:
            t.Log("Even")
        case 1, 3:
            t.Log("Odd")
        default:
            t.Log("it is not 0-3")
        }
    }
}

func TestSwitchCaseCondition(t *testing.T) {
    for i := 0; i < 5; i++ {
        switch {
        case i%2 == 0:
            t.Log(i)
            // fallthrough
        case i%2 == 1:
            t.Log(i)
            // fallthrough
        default:
            t.Log("unknown")
        }
    }
}

3.循環(huán):Go只支持for關(guān)鍵字。

舉個例子:

func TestWhileLoop(t *testing.T) {
    /* 模仿while循環(huán) */
    n := 0
    for n < 5 {
        t.Log(n)
        n++
    }

    // for循環(huán)
    for n := 0; n < 5; n++ {
        t.Log(n)
    }

    /* 死循環(huán) */
    for {
      //...
    }
}

七耸三、數(shù)組與切片

1.數(shù)組

  • 數(shù)組的聲明:
    var a [3]int // 聲明并初始化為默認(rèn)值0
    a[0] = 1     // 簡單賦值

    b := [3]int{1, 2, 3}           // 聲明的同時進(jìn)行初始化
    c := [2][2]int{{1, 2}, {3, 4}} // 聲明多維數(shù)組進(jìn)行初始化
  • 數(shù)組的遍歷:
func TestArrayTravel(t *testing.T) {
    arr := [...]int{1, 3, 4, 5}

    for i := 0; i < len(arr); i++ {
        t.Log(arr[i])
    }

    for _, element := range arr {
        t.Log(element)
    }

    for index, element := range arr {
        t.Log(index, element)
    }
}
  • 數(shù)組的截嚷叶浮:
func TestArraySection(t *testing.T) {
    arr := [...]int{1, 2, 3, 4, 5}
    arr_sec := arr[1:2]
    t.Log(arr_sec)
}

2.切片

切片是一種可變長的結(jié)構(gòu)體。(有點類似于iOS中的MutableArray

  • 切片的聲明:
    var s0 []int       // 聲明
    s0 = append(s0, 1) // 追加

    s := []int{}            // 聲明
    s1 := []int{1, 2, 3}    // 聲明并提供初始化值
    s2 := make([]int, 2, 4) //聲明并提供初始化個數(shù):2仪壮,max最大元素個數(shù):4憨颠。
    /*
        語法:make([]type, len, cap)
        其中l(wèi)en個元素會被初始化為默認(rèn)值0,未初始化的元素不可訪問积锅。
    */

1. 快速聲明語法:make([]type, len, cap)
其中爽彤,前len個元素會被初始化為默認(rèn)值0养盗,未初始化的元素不可訪問。(這是個容易造成crash的點适篙,不能越界操作爪瓜。)

2. 追加元素語法:s = append(s , element)
其中s代表切片,element代表追加的元素匙瘪。

  • 切片的簡單使用:
    直接上demo,
func TestSliceInit(t *testing.T) {
    var s0 []int
    t.Log(len(s0), cap(s0))

    s0 = append(s0, 1)
    t.Log(len(s0), cap(s0))

    s1 := []int{1, 2, 3, 4} // 快速初始化切片
    t.Log(len(s1), cap(s1))

    s2 := make([]int, 3, 5) // 初始化3個铆铆,max最大個數(shù)為5
    t.Log(len(s2), cap(s2))

    t.Log(s2[0], s2[1], s2[2])

    s2 = append(s2, 1) // 添加元素
    t.Log(s2[0], s2[1], s2[2], s2[3])
    // t.Log(s2[0], s2[1], s2[2], s2[3], s2[4])
}
  • 切片的原理:切片的共享存儲結(jié)構(gòu)。
    當(dāng)切片元素個數(shù)len超過cap時丹喻,會進(jìn)行2倍擴(kuò)容薄货。

八、Map(鍵值對Key: Value)

1.Map基本操作:

  • Map的三種初始化方式:
    /*
        第一種初始化方式:有初始值
    */
    m1 := map[string]int{"Key1": 1, "Key2": 2, "Key3": 3}
    t.Log(m1)
    t.Logf("len m1 = %d", len(m1))

    /*
        第二種初始化方式:無初始值
    */
    m2 := map[string]int{}
    m2["Key"] = 16
    t.Logf("len m2 = %d", len(m2))

    /*
        第三種初始化方式:初始化cap大邪邸(最大容量)谅猾,但len依然為0。(理由如下鳍悠,map不像數(shù)組有默認(rèn)值0税娜,所以len依然為0)
    */
    m3 := make(map[string]int, 10)
    t.Logf("len m3 = %d", len(m3))
  • Map元素的訪問:

當(dāng)訪問的Map不存在指定的Key時,會默認(rèn)返回0值藏研。
因此敬矩,Go語言中,不能通過Value是否為空來判斷Key是否存在蠢挡。

如果想要判斷Value是否存在弧岳,可用如下方式:

if value, ok := map[key]; ok {
  // 有值
} else {
  // 無值
}

Demo:

func TestAccessNotExistingKey(t *testing.T) {
    m1 := map[int]int{} // 初始化一個空map
    t.Log(m1[1])        // 隨便訪問一個Key?打印結(jié)果為0

    m1[2] = 0    // 設(shè)置一個Key(2)和Value(0)业踏。
    t.Log(m1[2]) // 打印一下還是0

    if value, ok := m1[3]; ok { // var v = m1[3], ok是表達(dá)式的bool值
        t.Logf("Key 3‘s value is %d", value)
    } else {
        t.Log("Key 3 is not existing.")
    }
}
  • Map的遍歷:

與遍歷數(shù)組for-range類似禽炬,但不同點在于 “數(shù)組返回的是index,Map返回的是Key” 勤家。

func TestTravelMap(t *testing.T) {
    map1 := map[string]int{"Key1": 1, "Key2": 2, "Key3": 3}
    for key, value := range map1 {
        t.Log(key, value)
    }
}

2.Map與工廠模式

  1. Map的 Value 可以是一個方法腹尖。
  2. 與Go的 Dock type 接口方式一起,可以方便的實現(xiàn)單一方法對象的工廠模式伐脖。
func TestMapWithFunValue(t *testing.T) {
    m := map[int]func(op int) int{}
    m[1] = func(op int) int { return op }
    m[2] = func(op int) int { return op * op }
    m[3] = func(op int) int { return op * op * op }
    t.Log(m[1](2), m[2](2), m[3](3))
}

3.在Go語言中實現(xiàn)Set

Go沒有Set的實現(xiàn)热幔,但可以通過map[type]bool來實現(xiàn)。

  1. 元素的唯一性
  2. 基本操作(添加元素晓殊、判斷元素是否存在断凶、刪除元素、元素個數(shù))
func TestMapForSet(t *testing.T) {
    mySet := map[int]bool{} // 初始化map
    mySet[1] = true         // 設(shè)置key巫俺、value
    n := 3
    if mySet[n] {
        t.Logf("%d is existing", n)
    } else {
        t.Logf("%d is not existing", n)
    }

    mySet[3] = true // 設(shè)置Key认烁、value
    t.Log(len(mySet))

    delete(mySet, 1) // 刪除Key為1的map
    t.Log(len(mySet))
}

九、字符串

與其他編程語言的差異:

  • string“值類型” ,而不是引用或指針類型却嗡。因此舶沛,默認(rèn)初始化時,會是一個""空的字符串窗价。(而不是nil

  • string是只讀的byte slice如庭,len函數(shù)返回的是string中的byte數(shù)。

  • string類型的byte數(shù)組可以存放任何數(shù)據(jù)撼港。

例如:

s = "\xE4\xB8\xA5" // 可以存儲任何二進(jìn)制數(shù)據(jù)
  • len求出來的是byte數(shù)坪它,并不是字符數(shù)。

問:Unicode 與 UTF8 的關(guān)系帝牡?
答:
Unicode是一種字符集往毡。(code point
UTF-8Unicode的存儲實現(xiàn)。(轉(zhuǎn)換為字節(jié)序列的規(guī)則)

舉個例子:

編碼 存儲
字符 "中"
Unicode 0x4E2D
UTF-8 0xE4B8AD
string/[]byte [0xE4, 0xB8, 0xAD]
  • 使用Go語言支持的strings靶溜、strconv庫:

首先开瞭,要導(dǎo)入strings和strconv庫:

import (
    "strconv"
    "strings"
)

字符串的分割與拼接的demo:

// 測試strings庫
func TestStringFunc(t *testing.T) {
    s := "A,B,C"
    parts := strings.Split(s, ",") // 字符串按","分割
    for _, part := range parts {
        t.Log(part)
    }
    t.Log(strings.Join(parts, "-")) // 字符串按"-"拼接
}

字符串轉(zhuǎn)型demo:

// 測試strconv庫
func TestConv(t *testing.T) {
    s := strconv.Itoa(10) // Int轉(zhuǎn)string
    t.Log("str" + s)

    if value, err := strconv.Atoi("10"); err == nil {
        t.Log(10 + value)
    } else {
        t.Log("轉(zhuǎn)換不成功!")
    }
    // t.Log(10 + strconv.Atoi("10")) // string轉(zhuǎn)Int罩息,編譯錯誤
}

十嗤详、函數(shù):是一等公民(可作為變量、參數(shù)瓷炮、返回值)

與其他編程語言的區(qū)別:

  • 函數(shù)可以有 多個返回值 葱色。

  • 所有參數(shù)都是 值傳遞 ,不是引用傳遞崭别。
    slice冬筒、map恐锣、channel會有傳引用的錯覺茅主。(slicemap土榴、channel本身是一個結(jié)構(gòu)體诀姚,其中會包含下一塊slicemap玷禽、channel的指針地址赫段。因此我們作為參數(shù)傳入函數(shù)的slicemap矢赁、channel實際上被復(fù)制了一份糯笙,但本身操作的其他對象依然會是原slicemapchannel的內(nèi)存地址撩银。)

這塊可能稍微有點繞给涕,可以看下slice的實現(xiàn)原理。(PS:可以參考“第七條”切片原理相關(guān)內(nèi)容)

  • 函數(shù)可以作為“變量”的值。

  • 函數(shù)可以作為“參數(shù)”“返回值”够庙。

重點:函數(shù)式編程(Go)

因為在Go語言中恭应,函數(shù)可以作為變量、參數(shù)耘眨、返回值昼榛。
因此,在編程習(xí)慣上與別的編程語言有些差異剔难。
需要開發(fā)者去慢慢適應(yīng)胆屿。

實戰(zhàn)小技巧

  1. 支持函數(shù)可變長參數(shù)

語法: [參數(shù)名] ...[參數(shù)類型]

PS:不指定參數(shù)個數(shù),但需要指定參數(shù)類型偶宫。

舉個例子莺掠,我們想寫個求和函數(shù),就可以這么寫:

// 求和函數(shù)
func sum(ops ...int) int {
    s := 0
    for _, op := range ops {
        s += op
    }
    return s
}
  1. 支持函數(shù)延時執(zhí)行读宙,多用于釋放資源(解鎖)

還是舉個例子:

// 模仿釋放資源的函數(shù)
func Clear() {
    fmt.Println("Clear resources.")
}

// 測試函數(shù)延時執(zhí)行:多用于釋放資源
func TestDefer(t *testing.T) {
    defer func() {
        // 用于釋放一些資源(鎖)
        Clear()
    }()
    fmt.Println("Started")
    panic("Fatal error") // panic:程序異常中斷彻秆,defer仍會執(zhí)行
}

最后,本系列我是在蔡超老師的技術(shù)分享下總結(jié)结闸、實戰(zhàn)完成的唇兑,
感謝蔡超老師的技術(shù)分享

PS:另附上桦锄,分享鏈接:《Go語言從入門到實戰(zhàn)》
祝大家學(xué)有所成扎附,工作順利。謝謝结耀!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末留夜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子图甜,更是在濱河造成了極大的恐慌碍粥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黑毅,死亡現(xiàn)場離奇詭異嚼摩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矿瘦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門枕面,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缚去,你說我怎么就攤上這事潮秘。” “怎么了易结?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵枕荞,是天一觀的道長稠通。 經(jīng)常有香客問我,道長买猖,這世上最難降的妖魔是什么改橘? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮玉控,結(jié)果婚禮上飞主,老公的妹妹穿的比我還像新娘。我一直安慰自己高诺,他們只是感情好碌识,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虱而,像睡著了一般筏餐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牡拇,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天魁瞪,我揣著相機(jī)與錄音,去河邊找鬼惠呼。 笑死导俘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剔蹋。 我是一名探鬼主播旅薄,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泣崩!你這毒婦竟也來了少梁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤矫付,失蹤者是張志新(化名)和其女友劉穎凯沪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體技即,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡著洼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了而叼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡豹悬,死狀恐怖葵陵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞻佛,我是刑警寧澤脱篙,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布娇钱,位于F島的核電站,受9級特大地震影響绊困,放射性物質(zhì)發(fā)生泄漏文搂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一秤朗、第九天 我趴在偏房一處隱蔽的房頂上張望煤蹭。 院中可真熱鬧,春花似錦取视、人聲如沸硝皂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稽物。三九已至,卻和暖如春折欠,著一層夾襖步出監(jiān)牢的瞬間贝或,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工锐秦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留傀缩,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓农猬,卻偏偏與公主長得像赡艰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斤葱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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