您现在的位置是:首页 >技术杂谈 >golang学习第三天网站首页技术杂谈

golang学习第三天

iceman0014 2026-07-04 00:01:04
简介golang学习第三天

今天学习的主要内容有Methods(方法)、interfaces(接口)、Type assertions(类型断言)、Stringers、Readers。老规矩先展示全部代码

package main

import (
    "fmt"
    "io"
    "math"
    "strings"
    "time"
)

// 声明结构体Vertex
type Vertex struct {
    X, Y float64
}

// 定义Vertex类型的方法Abs
func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

// 自定义类型
type MyFloat float64

// 定义MyFloat类型的方法Abs
func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

// 对象接收者类型Vertex
func (v Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
    fmt.Println("v1: ", v)
}

// 指针接收者类型*Vertex
func (v *Vertex) ScalePointer(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

// 指针接收者类型*Vertex
func (v *Vertex) AbsPointer() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

// 定义接口
type Abser interface {
    Abs() float64
}

// 定义接口
type I interface {
    M()
}

// 定义结构体
type T struct {
    S string
}

//  func (t T) M() {
//      fmt.Println(t.S)
//  }
//
// 给M方法添加指针接收者*T
func (t *T) M() {
    if t == nil {
        fmt.Println("<nil>")
        return
    }
    fmt.Println(t.S)
}

// 自定义类型F
type F float64

// 给M()方法添加对象接收者F
func (f F) M() {
    fmt.Println(f)
}

// 判断接口类型
func do(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("Twice %v is %v
", v, v*2)
    case string:
        fmt.Printf("%q is %v bytes long
", v, len(v))
    default:
        fmt.Printf("I don't know about type %T
", v)
    }
}

// 定义Person结构体
type Person struct {
    Name string
    Age  int
}

// person实现接口Stringers里的String()方法
func (p Person) String() string {
    return fmt.Sprintf("%v (%v years)
", p.Name, p.Age)
}

// 定义字节数组
type IPAddr [4]byte

// IPAddr实现接口Stringers里的String()方法
func (ip IPAddr) String() string {
    return fmt.Sprintf("%v.%v.%v.%v
", ip[0], ip[1], ip[2], ip[3])
}

// 自定义error结构体
type MyError struct {
    when time.Time
    what string
}

// MyError实现error接口中的Error方法
func (e *MyError) Error() string {
    return fmt.Sprintf("at %v %s
", e.when, e.what)
}

// 定义run方法返回一个MyError错误
func run() error {
    return &MyError{
        time.Now(),
        "it didn't work",
    }
}

// 自定义float64类型
type ErrNegativeSqrt float64

// ErrNegativeSqrt类型实现error接口中的Error方法
func (e ErrNegativeSqrt) Error() string {
    if e < 0 {
        return fmt.Sprintf("cannot sqrt negative number: %f
", e)
    }
    return ""
}

// Sqrt方法返回自定义错误
func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, ErrNegativeSqrt(f)
    }
    return math.Sqrt(f), ErrNegativeSqrt(f)
}

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

    f := MyFloat(-math.Sqrt2)
    fmt.Println(f.Abs())

    v.Scale(10)
    fmt.Println(v.Abs())

    p := &v
    fmt.Printf("Before scalling: %+v ,Abs: %v
", p, p.Abs())
    v.ScalePointer(5)
    // p.Scale(5)
    fmt.Printf("After scalling: %+v, Abs: %v
", p, p.Abs())

    //interface---------------------------------------------
    var a Abser
    a = f
    a = p
    fmt.Println(a)

    var i I

    describe(i)
    // i.M()

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

    var f1 = F(math.Pi)
    i = f1
    describe(i)
    i.M()

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

    var ii interface{}
    describe(ii)

    ii = 12
    describe(ii)

    ii = "Interface"
    describe(ii)

    // type ----------------------------------------
    var ai interface{} = "Hello"
    s := ai.(string)
    fmt.Println(s)

    af, ok := ai.(float64)
    fmt.Println(af, ok)

    //trigger a panic
    // af = ai.(float64)

    //type switches
    do(21)
    do("Type")
    do(true)

    //Stringers
    felix := Person{"Felix", 28}
    george := Person{"George", 30}
    fmt.Println(felix, george)

    hosts := map[string]IPAddr{
        "Kobbe": {127, 0, 0, 1},
        "James": {192, 168, 1, 1},
    }
    for name, ip := range hosts {
        fmt.Printf("%v : %v
", name, ip)
    }

    //error -------------------------------------
    if err := run(); err != nil {
        fmt.Println(err)
    }

    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))

    //readers --------------------------------
    r := strings.NewReader("Hello, Readers!")
    b := make([]byte, 8)
    for {
        n, err := r.Read(b)
        fmt.Printf("n=%v, err=%v, b=%v
", n, err, b)
        fmt.Printf("b[:n]=%q
", b[:n])
        if err == io.EOF {
            break
        }
    }

}

// 打印接口值和类型
func describe(i interface{}) {
    fmt.Printf("(%v, %T)
", i, i)
}

一、Methods方法

1.Go语言中没有class,但是可以给一个自定义类型添加方法,方法就是一个带有特殊接收者的函数,接收者定义要写在方法名称前,参照如下定义格式

type Vertex struct {

        X, Y float64

}

//给Abs方法添加接收者,类型是Vertex,名称是v

func (v Vertex) Abs() float64 {

        return math.Sqrt(v.X*v.X + v.Y*v.Y)

}

2.方法和带有接收者参数的函数是等价的,如下写法和1中的效果一样

func Abs(v Vertex) float64 {

        return math.Sqrt(v.X*v.X + v.Y*v.Y)

}

3.除了struct也可以给其他自定义类型添加方法

type MyFloat float64

func (f MyFloat) Abs() float64 {

        return float64(f)

}

4.指针接收者,可以给一个方法添加指针接收者,接收者的类型就是*T,好处是可以修改指针指向的数据,避免大数据类型的拷贝开销,实际编程中指针接收者使用频率更高一些。

type Vertex struct {

        X, Y float64

}

func (v Vertex) Abs() float64 {

        return math.Sqrt(v.X*v.X + v.Y*v.Y)

}

//定义指针接收者时,也可以通过对象来调用,go会自动进行转换

func (v *Vertex) Scale(f float64) {

        v.X = v.X * f

        v.Y = v.Y * f

}

func main() {

        v := Vertex{3, 4}

        v.Scale(10)  //和(&v).Scale(10)等价 

        fmt.Println(v.Abs()) //50

}

二、Interfaces接口

1.接口是一些方法声明的组合,实现了接口所有方法的变量可以赋值给接口变量,好处是可以通过接口来写一些公用方法,多态等

type Abser interface {

        Abs() float64

}

type MyFloat float64

func (f MyFloat) Abs() float64 {

        return float(f)

}

type Vertex struct {

        X, Y float64

}

func (v *Vertex) Abs() float64 {

        return math.Sqrt(v.X*v.X+v.Y*v.Y)

}

func main() {

        f := MyFloat(16)

        v := Vertex{3, 4}

        

        var a Abser

        a = f     //MyFloat 实现了Abser

        a = &v  //*Vertex实现了Abser

        a = v    //error Vertex没有实现Abser

        fmt.Println(a.Abs())     //5

 }

2.一个类型实现一个接口是通过实现接口里的方法,这个实现也可以在其他的package里,这里的接口中方法定义和实现是隔离开的,接口值可以看成一个元祖(value,type),每个接口变量都有明确的类型,这样执行接口方法是才能找到对应的实现

 type I interface {

        M()

}

type F float64

func (f F) M() {

        fmt.Println(f)

}

type T struct {

        S string

}

func (t *T) M() {

        fmt.Println(t.S)

}

func main () {

        var i I

        i = F(math.Pi)

        describe(i)

        i.M()

        

        i = &T{"Hello"}

        describe(i)

        i.M()

}

func describe(i I) {

        fmt.Printf("(%v, %T) ", i, i)

}

3.在Go中,nil接收者也是可以调用接口方法的

func (t *T) M() {

        if t == nil {

                 fmt.Println("<nil>")

                return

        }

        fmt.Println(t.S)

}

func main() {

        var i I

        i.M()  //panic: 当type和value都为nil时不可以调用M

        

        var t *T

        i = t

        i.M()  //可以调用成功

}

4.空接口可以被赋值为任意类型值

var i interface{}

i = 24

i = "Empty"

i = true

5.Type assertions类型断言,可以取出接口的实际值

var i interface{} = "Hello"

v, ok := i.(string)

fmt.Println(v, ok)

f = i.(float64) //panic

6.Type switches可以通过switch语句来判断接口类型

func do(i interface{}) {

        switch v:=i.(type) {

                case int:

                        fmt.Printf("Twice %v is %v ", v, v*2)

                case string:

                        fmt.Printf("%q is %v bytes long ", v, len(v))

                default:

                        fmt.Printf("I don't know about type %T ", v)

        }

}

func main () {

        do(20) // Twice 20 is 40

        do("hello") //hello is 5 bytes long

        do(true) //I don't know about type bool

}

三、Stringers

1.Stringer定义在fmt包中,实现了String方法后,通过fmt打印时会把自身按照string类型输出

type Stringer interface {

        String() string

}

type Person struct {

        Name string

        Age int

}

func (p Person) String() string {

        fmt.Printf("%v ( %v years) ", p.Name, p.Age)

}

func main() {

        a := Person{"Kobbe", 34}

        b := Person{"James", 40}

        fmt.Println(a,b)

}

四、Errors

1.Go中表示错误值用error状态

type Error interface {

        Error() string

}

type MyError struct {

        when time.Time

        what string

}

func (e *MyError) Error() string {

        return fmt.Sprintf("at %v %v ", 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)

        }

}

五、Readers

1.定义在io包中,用来读取stream数据,当stream结束时会返回io.EOF错误

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, err, b)

                fmt.Printf("b[:n]=%q ", 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] = ""

以上就是今天所学内容,明天继续。。。有问题欢迎一起讨论!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。