2019-05-22 Go語(yǔ)言學(xué)習(xí)三 方法和接口

1循集、方法

Go 沒(méi)有類掸哑。不過(guò)你可以為結(jié)構(gòu)體類型定義方法。
方法就是一類帶特殊的 **接收者** 參數(shù)的函數(shù)筋栋。
方法接收者在它自己的參數(shù)列表內(nèi)炊汤,位于 func 關(guān)鍵字和方法名之間。
在下面的例子中弊攘,Abs 方法擁有一個(gè)名為 v抢腐,類型為 Vertex 的接收者。

package main
import (
    "fmt"
    "math"
)
type Vertex struct {
    X, Y float64
}
func (v Vertex) Abs() float64 { //如果不用方法 直接寫(xiě) func Abs(v Vertex) float64 則運(yùn)行錯(cuò)誤
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
    v := Vertex{3, 4}
    fmt.Println(v.Abs())  // 運(yùn)行結(jié)果 5
}
  • 方法只是個(gè)帶接收者參數(shù)的函數(shù)襟交。
    現(xiàn)在這個(gè) Abs 的寫(xiě)法就是個(gè)正常的函數(shù)迈倍,功能并沒(méi)有什么變化。
//將Abs 改寫(xiě)成函數(shù)的形式
package main
import (
    "fmt"
    "math"
)
type Vertex struct {
    X, Y float64
}
func Abs(v Vertex) float64 { // 方法這里應(yīng)寫(xiě)成 func (v Vertex) Abs() float64 
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := Vertex{3, 4}
     fmt.Println(Abs(v)) // 方法的話 這里是是 fmt.Println(v.Abs())
}
1.2 方法續(xù)

也可以為非結(jié)構(gòu)體類型聲明方法捣域。
在此例中啼染,我們看到了一個(gè)帶 Abs 方法的數(shù)值類型 MyFloat宴合。
你只能為在同一包內(nèi)定義的類型的接收者聲明方法,而不能為其它包內(nèi)定義的類型(包括 int 之類的內(nèi)建類型)的接收者聲明方法迹鹅。
(譯注:就是接收者的類型定義和方法聲明必須在同一包內(nèi)卦洽;不能為內(nèi)建類型聲明方法。)

package main
import (
    "fmt"
    "math"
)

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

func main() {
    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs())
}

// 運(yùn)行結(jié)果:1.4142135623730951

2斜棚、指針

2.1 指針接受者

指針接收者的方法可以修改接收者指向的值
你可以為指針接收者聲明方法逐样。
這意味著對(duì)于某類型 T,接收者的類型可以用 *T 的文法打肝。(此外脂新,T 不能是像 *int 這樣的指針。)

例如粗梭,這里為 *Vertex 定義了 Scale 方法争便。
**指針接收者的方法可以修改接收者指向的值(就像 Scale 在這做的)。由于方法經(jīng)常需要修改它的接收者断医,指針接收者比值接收者更常用滞乙。 **
試著移除第 16 行 Scale 函數(shù)聲明中的 *,觀察此程序的行為如何變化鉴嗤。
若使用值接收者斩启,那么 Scale 方法會(huì)對(duì)原始 Vertex 值的副本進(jìn)行操作。(對(duì)于函數(shù)的其它參數(shù)也是如此醉锅。)Scale 方法必須用指針接受者來(lái)更改 main 函數(shù)中聲明的 Vertex 的值兔簇。

package main
import (
    "fmt"
    "math"
)
type Vertex struct {
    X, Y float64
}
func (v Vertex) Abs() float64 { // 這里Abs 是函數(shù)名 一般會(huì)用大寫(xiě) 當(dāng)然可以換成別的字母
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) { //這個(gè)地方如果去掉 * 則運(yùn)行結(jié)果變成 5
    v.X = v.X * f
    v.Y = v.Y * f
}
func main() {
    v := Vertex{3, 4}
    v.Scale(10)
    fmt.Println(v.Abs())
}

//運(yùn)行結(jié)果: 50
2.2 指針與函數(shù)

把 Abs 和 Scale 方法重寫(xiě)為函數(shù)

package main

import (
    "fmt"
    "math"
)

type Vertex struct {
    X, Y float64
}

func Abs(v Vertex) float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Scale(v *Vertex, f float64) { // 如果去掉 *  則編譯不通過(guò)
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    Scale(&v, 10)
    fmt.Println(Abs(v))
}

//運(yùn)行結(jié)果:50
2.3 方法與指針重定向

比較前兩個(gè)程序,你大概會(huì)注意到帶指針參數(shù)的函數(shù)必須接受一個(gè)指針:

var v Vertex
ScaleFunc(v, 5)  // 編譯錯(cuò)誤硬耍!
ScaleFunc(&v, 5) // OK

而以指針為接收者的方法被調(diào)用時(shí)垄琐,接收者既能為值又能為指針:

var v Vertex
v.Scale(5)  // OK
p := &v
p.Scale(10) // OK

對(duì)于語(yǔ)句 v.Scale(5),即便 v 是個(gè)值而非指針经柴,帶指針接收者的方法也能被直接調(diào)用狸窘。 也就是說(shuō),由于 Scale 方法有一個(gè)指針接收者坯认,為方便起見(jiàn)翻擒,Go 會(huì)將語(yǔ)句 v.Scale(5) 解釋為 (&v).Scale(5)。

//舉個(gè)例子
package main

import "fmt"

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func ScaleFunc(v *Vertex, f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    v.Scale(2)
    ScaleFunc(&v, 10)

    p := &Vertex{4, 3}
    p.Scale(3)
    ScaleFunc(p, 8)

    fmt.Println(v, p)
}

//運(yùn)行結(jié)果:{60 80} &{96 72}
方法與指針重定向(續(xù))

同樣的事情也發(fā)生在相反的方向牛哺。
接受一個(gè)值作為參數(shù)的函數(shù)必須接受一個(gè)指定類型的值:

var v Vertex
fmt.Println(AbsFunc(v))  // OK
fmt.Println(AbsFunc(&v)) // 編譯錯(cuò)誤陋气!

而以值為接收者的方法被調(diào)用時(shí),接收者既能為值又能為指針:

var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK

這種情況下荆隘,方法調(diào)用 p.Abs() 會(huì)被解釋為 (*p).Abs()恩伺。

package main

import (
    "fmt"
    "math"
)

type Vertex struct {
    X, Y float64
}

func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func AbsFunc(v Vertex) float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := Vertex{3, 4}
    fmt.Println(v.Abs()) //方法調(diào)用用v.Abs()
    fmt.Println(AbsFunc(v)) //函數(shù)調(diào)用用AbsFunc(v)

    p := &Vertex{4, 3}
    fmt.Println(p.Abs())
    fmt.Println(AbsFunc(*p))
}

// 運(yùn)行結(jié)果:
5
5
5
5
2.4 選擇值或指針作為接收者

**使用指針接收者的原因有二:
首先,方法能夠修改其接收者指向的值椰拒。
其次晶渠,這樣可以避免在每次調(diào)用方法時(shí)復(fù)制該值凰荚。若值的類型為大型結(jié)構(gòu)體時(shí),這樣做會(huì)更加高效褒脯。 **

在本例中便瑟,Scale 和 Abs 接收者的類型為 *Vertex,即便 Abs 并不需要修改其接收者番川。
通常來(lái)說(shuō)到涂,所有給定類型的方法都應(yīng)該有值或指針接收者,但并不應(yīng)該二者混用颁督。(我們會(huì)在接下來(lái)幾頁(yè)中明白為什么践啄。)

package main
import (
    "fmt"
    "math"
)
type Vertex struct {
    X, Y float64
}
func (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}
func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
    v := &Vertex{3, 4}
    fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
    v.Scale(5)
    fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}

// 運(yùn)行結(jié)果:
Before scaling: &{X:3 Y:4}, Abs: 5
After scaling: &{X:15 Y:20}, Abs: 25

3、接口

3.1 接口介紹

**接口類型 是由一組方法簽名定義的集合沉御。 **
接口類型的變量可以保存任何實(shí)現(xiàn)了這些方法的值屿讽。

3.2 接口與隱式實(shí)現(xiàn)

類型通過(guò)實(shí)現(xiàn)一個(gè)接口的所有方法來(lái)實(shí)現(xiàn)該接口。既然無(wú)需專門顯式聲明吠裆,也就沒(méi)有“implements”關(guān)鍵字伐谈。
隱式接口從接口的實(shí)現(xiàn)中解耦了定義,這樣接口的實(shí)現(xiàn)可以出現(xiàn)在任何包中试疙,無(wú)需提前準(zhǔn)備诵棵。
因此,也就無(wú)需在每一個(gè)實(shí)現(xiàn)上增加新的接口名稱祝旷,這樣同時(shí)也鼓勵(lì)了明確的接口定義履澳。

package main
import "fmt"
type I interface {
    M()
}
type T struct {
    S string
}

// 此方法表示類型 T 實(shí)現(xiàn)了接口 I,但我們無(wú)需顯式聲明此事缓屠。
func (t T) M() {
    fmt.Println(t.S)
}

func main() {
    var i I = T{"hello"}
    i.M()
}

//運(yùn)行結(jié)果:hello
3.3 接口值

接口也是值奇昙。它們可以像其它值一樣傳遞。
接口值可以用作函數(shù)的參數(shù)或返回值敌完。
在內(nèi)部,接口值可以看做包含值和具體類型的元組:
(value, type)
接口值保存了一個(gè)具體底層類型的具體值羊初。
接口值調(diào)用方法時(shí)會(huì)執(zhí)行其底層類型的同名方法

package main

import (
    "fmt"
    "math"
)

type I interface {
    M()
}

type T struct {
    S string
}

func (t *T) M() {
    fmt.Println(t.S)
}

type F float64

func (f F) M() {
    fmt.Println(f)
}

func main() {
    var i I

    i = &T{"Hello"}
    describe(i)
    i.M()

    i = F(math.Pi)
    describe(i)
    i.M()
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}

--------------------------------------------------------------------
//運(yùn)行結(jié)果:
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793

3.4 底層值為nil的接口值

即便接口內(nèi)的具體值為 nil滨溉,方法仍然會(huì)被 nil 接收者調(diào)用。
在一些語(yǔ)言中长赞,這會(huì)觸發(fā)一個(gè)空指針異常晦攒,但在 Go 中通常會(huì)寫(xiě)一些方法來(lái)優(yōu)雅地處理它(如本例中的 M 方法)。
注意: 保存了 nil 具體值的接口其自身并不為 nil得哆。

package main

import "fmt"

type I interface {
    M()
}

type T struct {
    S string
}

func (t *T) M() {
    if t == nil {
        fmt.Println("<nil>")
        return
    }
    fmt.Println(t.S)
}

func main() {
    var i I

    var t *T
    i = t
    describe(i)
    i.M()

    i = &T{"hello"}
    describe(i)
    i.M()
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}

-------------------------------------------------------------------------
//輸出結(jié)果:
(<nil>, *main.T)
<nil>
(&{hello}, *main.T)
hello

3.5 nil接口值

nil 接口值既不保存值也不保存具體類型脯颜。

3.6 空接口

指定了零個(gè)方法的接口值被稱為 空接口:
interface{}
空接口可保存任何類型的值。(因?yàn)槊總€(gè)類型都至少實(shí)現(xiàn)了零個(gè)方法贩据。)
空接口被用來(lái)處理未知類型的值栋操。例如闸餐,fmt.Print 可接受類型為 interface{} 的任意數(shù)量的參數(shù)。

package main

import "fmt"

func main() {
    var i interface{}
    describe(i)

    i = 42
    describe(i)

    i = "hello"
    describe(i)
}

func describe(i interface{}) {
    fmt.Printf("(%v, %T)\n", i, i)
}

------------------------------------------------------------------------
//運(yùn)行結(jié)果:
(<nil>, <nil>)
(42, int)
(hello, string)

4矾芙、類型

4.1 類型斷言

類型斷言 提供了訪問(wèn)接口值底層具體值的方式舍沙。

t := i.(T)

該語(yǔ)句斷言接口值 i 保存了具體類型 T,并將其底層類型為 T 的值賦予變量 t剔宪。
若 i 并未保存 T 類型的值拂铡,該語(yǔ)句就會(huì)觸發(fā)一個(gè)恐慌。
為了 判斷 一個(gè)接口值是否保存了一個(gè)特定的類型葱绒,類型斷言可返回兩個(gè)值:其底層值以及一個(gè)報(bào)告斷言是否成功的布爾值感帅。

t, ok := i.(T)

若 i 保存了一個(gè) T,那么 t 將會(huì)是其底層值地淀,而 ok 為 true留瞳。
否則,ok 將為 false 而 t 將為 T 類型的零值骚秦,程序并不會(huì)產(chǎn)生恐慌她倘。
請(qǐng)注意這種語(yǔ)法和讀取一個(gè)映射時(shí)的相同之處。

package main
import "fmt"
func main() {
    var i interface{} = "hello"

    s := i.(string)
    fmt.Println(s)

    s, ok := i.(string)
    fmt.Println(s, ok)

    f, ok := i.(float64)
    fmt.Println(f, ok)

    f = i.(float64) // 報(bào)錯(cuò)(panic)
    fmt.Println(f)
}

運(yùn)行結(jié)果:

hello true
0 false
panic: interface conversion: interface {} is string, not float64
4.2 類型選擇

類型選擇 是一種按順序從幾個(gè)類型斷言中選擇分支的結(jié)構(gòu)作箍。

類型選擇與一般的 switch 語(yǔ)句相似硬梁,不過(guò)類型選擇中的 case 為類型(而非值), 它們針對(duì)給定接口值所存儲(chǔ)的值的類型進(jìn)行比較胞得。

switch v := i.(type) {
case T:
    // v 的類型為 T
case S:
    // v 的類型為 S
default:
    // 沒(méi)有匹配荧止,v 與 i 的類型相同
}

類型選擇中的聲明與類型斷言 i.(T) 的語(yǔ)法相同,只是具體類型 T 被替換成了關(guān)鍵字 type阶剑。

此選擇語(yǔ)句判斷接口值 i 保存的值類型是 T 還是 S跃巡。在 T 或 S 的情況下,變量 v 會(huì)分別按 T 或 S 類型保存 i 擁有的值牧愁。在默認(rèn)(即沒(méi)有匹配)的情況下素邪,變量 v 與 i 的接口類型和值相同。

package main
import "fmt"
func do(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("Twice %v is %v\n", v, v*2)
    case string:
        fmt.Printf("%q is %v bytes long\n", v, len(v))
    default:
        fmt.Printf("I don't know about type %T!\n", v)
    }
}

func main() {
    do(21)
    do("hello")
    do(true)
}

---------------------------------------------------------------------------------
//運(yùn)行結(jié)果:
Twice 21 is 42
"hello" is 5 bytes long
I don't know about type bool!

5猪半、Stringer

fmt 包中定義的 Stringer 最普遍的接口之一兔朦。

type Stringer interface {
    String() string
}

Stringer 是一個(gè)可以用字符串描述自己的類型。fmt 包(還有很多包)都通過(guò)此接口來(lái)打印值磨确。

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

func main() {
    a := Person{"Arthur Dent", 42}
    z := Person{"Zaphod Beeblebrox", 9001}
    fmt.Println(a, z)
}

// 運(yùn)行結(jié)果:
Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)

練習(xí):Stringer
通過(guò)讓 IPAddr 類型實(shí)現(xiàn) fmt.Stringer 來(lái)打印點(diǎn)號(hào)分隔的地址沽甥。
例如,IPAddr{1, 2, 3, 4} 應(yīng)當(dāng)打印為 "1.2.3.4"乏奥。

package main
import "fmt"
type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (p IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v", p[0], p[1], p[2], p[3]);
}

func main() {
    hosts := map[string]IPAddr{
        "loopback":  {127, 0, 0, 1},
        "googleDNS": {8, 8, 8, 8},
    }
    for name, ip := range hosts {
        fmt.Printf("%v: %v\n", name, ip)
    }
}

----------------------------------------------------
// 運(yùn)行結(jié)果:
loopback: 127.0.0.1
googleDNS:8.8.8.8

6摆舟、錯(cuò)誤

Go 程序使用 error 值來(lái)表示錯(cuò)誤狀態(tài)。
與 fmt.Stringer 類似,error 類型是一個(gè)內(nèi)建接口:

type error interface {
    Error() string
}

(與 fmt.Stringer 類似恨诱,fmt 包在打印值時(shí)也會(huì)滿足 error媳瞪。)
通常函數(shù)會(huì)返回一個(gè) error 值,調(diào)用的它的代碼應(yīng)當(dāng)判斷這個(gè)錯(cuò)誤是否等于 nil 來(lái)進(jìn)行錯(cuò)誤處理胡野。

i, err := strconv.Atoi("42")
if err != nil {
    fmt.Printf("couldn't convert number: %v\n", err)
    return
}
fmt.Println("Converted integer:", i)

error 為 nil 時(shí)表示成功材失;非 nil 的 error 表示失敗。

package main
import (
    "fmt"
    "time"
)
type MyError struct {
    When time.Time
    What string
}
func (e *MyError) Error() string {
    return fmt.Sprintf("at %v, %s",
        e.When, e.What)
}
func run() error {
    return &MyError{
        time.Now(),
        "it didn't work",
    }
}
func main() {
    if err := run(); err != nil {
        fmt.Println(err)
    }
}

// 運(yùn)行結(jié)果: at 2019-05-22 17:57:45.797632243 +0800 CST m=+0.000720070, it didn't work

練習(xí):錯(cuò)誤

之前的練習(xí)中復(fù)制 Sqrt 函數(shù)硫豆,修改它使其返回 error 值龙巨。

Sqrt 接受到一個(gè)負(fù)數(shù)時(shí),應(yīng)當(dāng)返回一個(gè)非 nil 的錯(cuò)誤值熊响。復(fù)數(shù)同樣也不被支持旨别。

創(chuàng)建一個(gè)新的類型

type ErrNegativeSqrt float64

并為其實(shí)現(xiàn)

func (e ErrNegativeSqrt) Error() string

方法使其擁有 error 值,通過(guò) ErrNegativeSqrt(-2).Error() 調(diào)用該方法應(yīng)返回 "cannot Sqrt negative number: -2"汗茄。

注意:Error 方法內(nèi)調(diào)用 fmt.Sprint(e) 會(huì)讓程序陷入死循環(huán)秸弛。可以通過(guò)先轉(zhuǎn)換 e 來(lái)避免這個(gè)問(wèn)題:fmt.Sprint(float64(e))洪碳。這是為什么呢递览?

修改 Sqrt 函數(shù),使其接受一個(gè)負(fù)數(shù)時(shí)瞳腌,返回 ErrNegativeSqrt 值绞铃。

package main

import (
    "fmt"
    "math"
)

func Sqrt(x float64) (float64, error) {
    if x < 0 {
        return 0, ErrNegativeSqrt(x)
    }

     z := float64(1)
     for {
          y := z - (z*z-x)/(2*z)
          if math.Abs(y-z) < 1e-10 {
               return y, nil
          }
          z = y
     }
     return z, nil
}


type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}


func main() {
    fmt.Println(Sqrt(2)) // 1.4142135623730951 <nil>
    fmt.Println(Sqrt(-2)) // 0 cannot Sqrt negative number: -2
}

7、Reader

**io 包指定了 io.Reader 接口嫂侍,它表示從數(shù)據(jù)流的末尾進(jìn)行讀取儿捧。 **
io.Reader 接口有一個(gè) Read 方法:

func (T) Read(b []byte) (n int, err error)  

Read 用數(shù)據(jù)填充給定的字節(jié)切片并返回填充的字節(jié)數(shù)和錯(cuò)誤值。在遇到數(shù)據(jù)流的結(jié)尾時(shí)挑宠,它會(huì)返回一個(gè) io.EOF 錯(cuò)誤菲盾。

示例代碼創(chuàng)建了一個(gè) strings.Reader 并以每次 8 字節(jié)的速度讀取它的輸出。

package main

import (
    "fmt"
    "io"
    "strings"
)

func main() {
    r := strings.NewReader("Hello, Reader!")

    b := make([]byte, 8)
    for {
        n, err := r.Read(b)
        fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
        fmt.Printf("b[:n] = %q\n", b[:n])
        if err == io.EOF {
            break
        }
    }
}

運(yùn)行結(jié)果:

b[:n] = "Hello, R"
n = 6 err = <nil> b = [101 97 100 101 114 33 32 82]
b[:n] = "eader!"
n = 0 err = EOF b = [101 97 100 101 114 33 32 82]
b[:n] = ""

8各淀、圖像

image 包定義了 Image 接口:

package image

type Image interface {
    ColorModel() color.Model
    Bounds() Rectangle
    At(x, y int) color.Color
}

注意: Bounds 方法的返回值 Rectangle 實(shí)際上是一個(gè) image.Rectangle懒鉴,它在 image 包中聲明。
color.Colorcolor.Model 類型也是接口揪阿,但是通常因?yàn)橹苯邮褂妙A(yù)定義的實(shí)現(xiàn) image.RGBAimage.RGBAModel 而被忽視了疗我。這些接口和類型由 image/color 包定義。

package main

import (
    "fmt"
    "image"
)

func main() {
    m := image.NewRGBA(image.Rect(0, 0, 100, 100))
    fmt.Println(m.Bounds()) //(0,0)-(100,100)
    fmt.Println(m.At(0, 0).RGBA()) //0 0 0 0
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末南捂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子旧找,更是在濱河造成了極大的恐慌溺健,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鞭缭,居然都是意外死亡剖膳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門岭辣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吱晒,“玉大人,你說(shuō)我怎么就攤上這事沦童÷乇簦” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵偷遗,是天一觀的道長(zhǎng)墩瞳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)氏豌,這世上最難降的妖魔是什么喉酌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮泵喘,結(jié)果婚禮上泪电,老公的妹妹穿的比我還像新娘。我一直安慰自己纪铺,他們只是感情好相速,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著霹陡,像睡著了一般和蚪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烹棉,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天攒霹,我揣著相機(jī)與錄音,去河邊找鬼浆洗。 笑死催束,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伏社。 我是一名探鬼主播抠刺,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼摘昌!你這毒婦竟也來(lái)了速妖?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤聪黎,失蹤者是張志新(化名)和其女友劉穎罕容,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锦秒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年哈雏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歌逢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栖疑。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡预麸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出生真,到底是詐尸還是另有隱情沉噩,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布汇歹,位于F島的核電站屁擅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏产弹。R本人自食惡果不足惜派歌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望痰哨。 院中可真熱鬧胶果,春花似錦、人聲如沸斤斧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撬讽。三九已至蕊连,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間游昼,已是汗流浹背甘苍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烘豌,地道東北人载庭。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像廊佩,于是被迫代替她去往敵國(guó)和親囚聚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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

  • 方法和接口 第四篇包含了方法和接口标锄,可以用它們來(lái)定義對(duì)象和其行為顽铸;以及如何將所有內(nèi)容貫通起來(lái)。 方法 Go 沒(méi)有類...
    張洋銘Ocean閱讀 1,473評(píng)論 2 0
  • 原文鏈接 http://ironxu.com/701 本文是學(xué)習(xí) A Tour of Go (中文參考 Go 之旅...
    好剛編程閱讀 760評(píng)論 0 7
  • 方法 Go中沒(méi)有類料皇,但是可以為結(jié)構(gòu)體定義方法跋破,方法就是一類帶有特殊的接受者參數(shù)的函數(shù)簸淀。方法接受者在它自己的參數(shù)列表...
    EvansChang閱讀 347評(píng)論 0 0
  • 方法 Go語(yǔ)言中的方法其實(shí)就是一個(gè)特殊函數(shù), 只不過(guò)這個(gè)函數(shù)是和某種屬性類型綁定在一起的而已 Go語(yǔ)言中的方法一般...
    極客江南閱讀 937評(píng)論 0 4
  • 一瓶蝴、方法 Go 沒(méi)有類毒返。然而,仍然可以在結(jié)構(gòu)體類型上定義方法舷手。 方法接收者 出現(xiàn)在 func 關(guān)鍵字和方法名之間的...
    liycode閱讀 370評(píng)論 0 1