Go言語基本文法(4) ~method, interface, error, panic~

メソッド

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 main() {
    v := Vertex{3, 4}
    fmt.Println(v.Abs())
    // 5
 
    x := Vertex{5, 12}
    fmt.Println(x.Abs())
    // 13
}
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())
    // 1.4142135623730951
}
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 (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    fmt.Println(v.Abs())
    // 5
 
    v.Scale(10)
    fmt.Println(v.Abs())
    // 50
}
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) {
    v.X = v.X * f
    v.Y = v.Y * f
}

func main() {
    v := Vertex{3, 4}
    fmt.Println(Abs(v))
    // 5
 
    Scale(&v, 10)
    fmt.Println(Abs(v))
    // 50
}
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}
    fmt.Println(v)
    // {3 4}
 
    v.Scale(2)
    fmt.Println(v)
    // {6 8}
 
    ScaleFunc(&v, 10)
    fmt.Println(v)
    // {60 80}
}
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())
    // 5
    fmt.Println(AbsFunc(v))
    // 5

    p := &Vertex{4, 3}
    fmt.Println(p.Abs()) // (*p).Abs()と解釈される
    // 5
    fmt.Println(AbsFunc(*p)) // AbsFunc(p)とするとエラー
    // 5
}

interface

package main

import (
    "fmt"
    "math"
)

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}
 
    a = f
    fmt.Println(a.Abs())
    // 1.4142135623730951
 
    a = &v
    fmt.Println(a.Abs())
    // 5
 
    // エラー
    // a = v
    // VertexはAbs()を持っていない
    // Abs()を持っているのは*Vertex
}

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)
}
package main

import "fmt"

type I interface {
    M()
}

type T struct {
    S string
}

// ここで、T はinterface I を実装することを意味しています
// しかしそのことを明示的に宣言する必要はありません
func (t T) M() {
    fmt.Println(t.S)
}

func main() {
    var i I = T{"hello"}
    i.M()
    // hello
}
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)
    // (&{Hello}, *main.T)
    i.M()
    // Hello

    i = F(math.Pi)
    describe(i)
    // (3.141592653589793, main.F)
    i.M()
    // 3.141592653589793
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}
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)
    // (<nil>, *main.T)
    i.M()
    // <nil>

    i = &T{"hello"}
    describe(i)
    // (&{hello}, *main.T)
    i.M()
    // hello
}

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

import "fmt"

func main() {
    // 空のインターフェース
    var i interface{}
    describe(i)
    // (<nil>, <nil>)

    // どの型でも受け入れられる
    i = 42
    describe(i)
    // (42, int)
 
    i = "hello"
    describe(i)
    // (hello, string)
}

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

Type assertions

package main

import "fmt"

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

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

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

    f, ok := i.(float64)
    fmt.Println(f, ok)
    // 0 false
 
    // panic
    // f = i.(float64)
    // fmt.Println(f)
}
package main

import "fmt"

func do(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Println(v)
    case string:
        fmt.Println(v)
    default:
        fmt.Printf("I don't know about type %T!\n", v)
    }
}

func main() {
    do(21)
    // 21
    do("hello")
    // hello
    do(true)
    // I don't know about type bool!
}

Stringers

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}
    fmt.Println(a)
    // Arthur Dent (42 years)
}

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

// errorは組み込みのinterface
// type error interface {
//    Error() string
// }
func run() error {
    return &MyError{time.Now(), "it didn't work",}
}

func main() {
    if err := run(); err != nil {fmt.Println(err)}
    // at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't work
}

panic

エラーを故意に起こすやつ

a := []int{1, 2, 3}
for i := 0; i < 10; i++ {
    if i >= len(a) {
        panic(errors.New("index out of range"))
    }
    fmt.Println(a[i])
}

Reader

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
        }
    }
    // 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] = ""
}

参考

A Tour of Go