1. 程式人生 > >go學習筆記-面向物件(Methods, Interfaces)

go學習筆記-面向物件(Methods, Interfaces)

面向物件(Methods, Interfaces)

Method

method是附屬在一個給定的型別上的,他的語法和函式的宣告語法幾乎一樣,只是在func後面增加了一個receiver(也就是method所依從的主體)。

語法

func (r ReceiverType) funcName(parameters) (results)

示例

type rectangle struct {
    width  float64
    heigth float64
}

func (receiver rectangle) area() float64 {
    return receiver.width * receiver.heigth
}

func main(){
    rect := rectangle{heigth: 12, width: 12}
    area := rect.area()
    fmt.Println(area)
}

注意

  • 接收者不一樣,那麼method就不一樣
  • method裡面可以訪問接收者的欄位
  • 呼叫method通過.訪問,就像struct裡面訪問欄位一樣
  • 定義在任何你自定義的型別、內建型別、struct等各種型別上面
  • 如果想要改變接受者的內容,可以使用指標

interface

簡單的說,interface是一組method簽名的組合,我們通過interface來定義物件的一組行為

/* 定義介面 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定義結構體 */
type struct_name struct {
   /* variables */
}

/* 實現介面方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法實現 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
   /* 方法實現*/
}

interface型別定義了一組方法,如果某個物件實現了某個介面的所有方法,則此物件就實現了此介面。

type Isay interface {
    say(word string) string
}

type dog struct {
    name string
}

type cat struct {
    sex string
}

func (d dog) say(word string) string {
    return d.name + word
}

func (c cat) say(word string) string {
    return "cat=" + word
}

//使用
var idg, icat Isay
idg = dog{"dog"}
fmt.Println(idg.say("hello"))
icat = cat{"0"}
fmt.Println(icat.say("world"))

最後,任意的型別都實現了空interface(我們這樣定義:interface{}),也就是包含0個method的interface。

型別判斷

Comma-ok斷言

Go語言裡面有一個語法,可以直接判斷是否是該型別的變數: value, ok = element.(T),這裡value就是變數的值,ok是一個bool型別,element是interface變數,T是斷言的型別。

如果element裡面確實儲存了T型別的數值,那麼ok返回true,否則返回false。

package main

import (
    "fmt"
    "strconv"
)

type Element interface{}
type List [] Element

type Person struct {
    name string
    age int
}

//定義了String方法,實現了fmt.Stringer
func (p Person) String() string {
    return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
}

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

    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\n", index, value)
        } else {
            fmt.Printf("list[%d] is of a different type\n", index)
        }
    }
}

if-else過多,可以使用switch代替

package main

import (
    "fmt"
    "strconv"
)

type Element interface{}
type List [] Element

type Person struct {
    name string
    age int
}

//列印
func (p Person) String() string {
    return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
}

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

    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\n", index, value)
            default:
                fmt.Println("list[%d] is of a different type", index)
        }
    }
}

這裡有一點需要強調的是:element.(type)語法不能在switch外的任何邏輯裡面使用,如果你要在switch外面判斷一個型別就使用comma-ok