【技術】Golang進階(一)

本篇內容包括:

  • 方法

方法

Go 沒有類。然而,仍然可以在結構體類型上定義方法。
方法接收者 出現(xiàn)在 func 關鍵字和方法名之間的參數(shù)中。

type Vertex struct {
    X, Y float64
}
// 類似于Java中點語法實現(xiàn)
func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

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

可以對包中的 任意 類型定義任意方法掺涛,而不僅僅是針對結構體。
但是疼进,不能對來自其他包的類型或基礎類型定義方法薪缆。

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())
}

接收者為指針的方法
方法可以與命名類型或命名類型的指針關聯(lián)。
剛剛看到的兩個 Abs 方法伞广。一個是在 *Vertex 指針類型上拣帽,而另一個在 MyFloat 值類型上疼电。 有兩個原因需要使用指針接收者。首先避免在每個方法調用中拷貝值(如果值類型是大的結構體的話會更有效率)减拭。其次蔽豺,方法可以修改接收者指向的值。
嘗試修改 Abs 的定義拧粪,同時 Scale 方法使用 Vertex 代替 *Vertex 作為接收者修陡。
當 v 是 Vertex 的時候 Scale 方法沒有任何作用。Scale 修改 v可霎。當 v 是一個值(非指針)魄鸦,方法看到的是 Vertex 的副本,并且無法修改原始值癣朗。
Abs 的工作方式是一樣的拾因。只不過,僅僅讀取 v斯棒。所以讀取的是原始值(通過指針)還是那個值的副本并沒有關系盾致。

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}
    v.Scale(5)
    fmt.Println(v, v.Abs())
}

接口

接口類型是由一組方法定義的集合主经。
接口類型的值可以存放實現(xiàn)這些方法的任何值荣暮。

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat 實現(xiàn)了 Abser
    a = &v // a *Vertex 實現(xiàn)了 Abser

    // 下面一行,v 是一個 Vertex(而不是 *Vertex)
    // 所以沒有實現(xiàn) Abser罩驻。
    a = v

    fmt.Println(a.Abs())
}

type MyFloat float64

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

type Vertex struct {
    X, Y float64
}

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

隱式接口
類型通過實現(xiàn)那些方法來實現(xiàn)接口穗酥。 沒有顯式聲明的必要;所以也就沒有關鍵字“implements“惠遏。
隱式接口解藕了實現(xiàn)接口的包和定義接口的包:互不依賴砾跃。
因此,也就無需在每一個實現(xiàn)上增加新的接口名稱节吮,這樣同時也鼓勵了明確的接口定義

type Reader interface {
    Read(b []byte) (n int, err error)
}

type Writer interface {
    Write(b []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

func main() {
    var w Writer

    // os.Stdout 實現(xiàn)了 Writer
    w = os.Stdout

    fmt.Fprintf(w, "hello, writer\n")
}

Stringers

一個普遍存在的接口是 fmt 包中定義的 Stringer抽高。

type Stringer struct {
    String() string
}

Stringer 是一個可以用字符串描述自己的類型。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)
}
// Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)

錯誤

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

type error interface {
    Error() string
}
(與 fmt.Stringer 類似帚豪,`fmt` 包在輸出時也會試圖匹配 `error`碳竟。)

通常函數(shù)會返回一個 error 值,調用的它的代碼應當判斷這個錯誤是否等于 nil狸臣, 來進行錯誤處理莹桅。

i, err := strconv.Atoi("42")
if err != nil {
    fmt.Printf("couldn't convert number: %v\n", err)
}
fmt.Println("Converted integer:", i)
error 為 nil 時表示成功;非 nil 的 error 表示錯誤烛亦。
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)
    }
}
// at 2018-04-18 23:21:57.492848045 +0800 CST m=+0.000363471, it didn't work

Reader

io 包指定了 io.Reader 接口诈泼, 它表示從數(shù)據(jù)流結尾讀取懂拾。
Go 標準庫包含了這個接口的許多實現(xiàn), 包括文件厂汗、網(wǎng)絡連接委粉、壓縮、加密等等娶桦。
io.Reader 接口有一個 Read 方法:

func (T) Read(b []byte) (n int, err error)</pre>

Read 用數(shù)據(jù)填充指定的字節(jié) slice贾节,并且返回填充的字節(jié)數(shù)和錯誤信息。 在遇到數(shù)據(jù)流結尾時衷畦,返回 io.EOF 錯誤栗涂。
例子代碼創(chuàng)建了一個 strings.Reader。 并且以每次 8 字節(jié)的依次讀取它的輸出祈争。

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
        }
    }
}
/*
n = 8 err = <nil> b = [72 101 108 108 111 44 32 82]
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] = ""
*/

利用 rot13 代換密碼對數(shù)據(jù)流進行修改斤程。

type rot13Reader struct {
    r io.Reader
}
// 轉換byte  前進13位/后退13位
func rot13(b byte) byte {
    switch {
    case 'A' <= b && b <= 'M':
        b = b + 13
    case 'M' < b && b <= 'Z':
        b = b - 13
    case 'a' <= b && b <= 'm':
        b = b + 13
    case 'm' < b && b <= 'z':
        b = b - 13
    }
    return b
}
// 重寫Read方法
func (mr rot13Reader) Read(b []byte) (int, error) {
    n, e := mr.r.Read(b)
    for i := 0; i < n; i++ {
        b[i] = rot13(b[i])
    }
    return n, e
}
func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}

Web 服務器

包 http 通過任何實現(xiàn)了 http.Handler 的值來響應 HTTP 請求:

package http
type Handler interface {
    ServeHTTP(w ResponseWriter, r *Request)
}

在這個例子中,類型 Hello 實現(xiàn)了 http.Handler菩混。

type Hello struct{}

func (h Hello) ServeHTTP(
    w http.ResponseWriter,
    r *http.Request) {
    fmt.Fprint(w, "Hello!")
}

func main() {
    var h Hello
    err := http.ListenAndServe("localhost:4000", h)
    if err != nil {
        log.Fatal(err)
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末忿墅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沮峡,更是在濱河造成了極大的恐慌疚脐,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邢疙,死亡現(xiàn)場離奇詭異棍弄,居然都是意外死亡,警方通過查閱死者的電腦和手機疟游,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門呼畸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颁虐,你說我怎么就攤上這事蛮原。” “怎么了另绩?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵儒陨,是天一觀的道長。 經(jīng)常有香客問我板熊,道長框全,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任干签,我火速辦了婚禮津辩,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己喘沿,他們只是感情好闸度,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚜印,像睡著了一般莺禁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窄赋,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天哟冬,我揣著相機與錄音,去河邊找鬼忆绰。 笑死浩峡,一個胖子當著我的面吹牛,可吹牛的內容都是我干的错敢。 我是一名探鬼主播翰灾,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稚茅!你這毒婦竟也來了纸淮?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤亚享,失蹤者是張志新(化名)和其女友劉穎咽块,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虹蒋,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡糜芳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年飒货,在試婚紗的時候發(fā)現(xiàn)自己被綠了魄衅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡塘辅,死狀恐怖晃虫,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情扣墩,我是刑警寧澤哲银,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站呻惕,受9級特大地震影響荆责,放射性物質發(fā)生泄漏。R本人自食惡果不足惜亚脆,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一做院、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦键耕、人聲如沸寺滚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽村视。三九已至,卻和暖如春酒奶,著一層夾襖步出監(jiān)牢的瞬間蚁孔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工惋嚎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留勒虾,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓瘸彤,卻偏偏與公主長得像修然,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子质况,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容

  • 方法和接口 第四篇包含了方法和接口愕宋,可以用它們來定義對象和其行為;以及如何將所有內容貫通起來结榄。 方法 Go 沒有類...
    張洋銘Ocean閱讀 1,473評論 2 0
  • 出處---Go編程語言 歡迎來到 Go 編程語言指南中贝。本指南涵蓋了該語言的大部分重要特性 Go 語言的交互式簡介,...
    Tuberose閱讀 18,409評論 1 46
  • 1.安裝 https://studygolang.com/dl 2.使用vscode編輯器安裝go插件 3.go語...
    go含羞草閱讀 1,541評論 0 6
  • 開始寫這件事以后臼朗,常常覺得寫什么都是別人寫過的邻寿,想破腦袋也想不出寫什么大家會喜歡看! 相對于別人的肯定视哑,我現(xiàn)在覺得...
    萬年修得王小順閱讀 167評論 1 1
  • 在大片大片惹情的禾田 和玉米地绣否,在蛙聲和布谷鳥的歌聲 邊緣,我記得她們 有高挑而纖細的身材 灌滿北方的空曠和蒹葭的...
    伊東川閱讀 419評論 0 1