Go语言基础

Posted 想考北航的小刺猬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言基础相关的知识,希望对你有一定的参考价值。

Method

  • go语言没有类这个概念,但是但可以在类型上定义method,method是一个带有指定receiver参数的函数,receiver出现在自己的参数列表中,并且位于func关键字和method名之间,Abs方法有一个类型为Vertex命名为v的receiver。
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 := Vertex34
	fmt.Println(v.Abs())


func add(x, y int) int

  • method只是一个带有receiver参数的函数
  • 也能够用非结构类型定义method,但是不能用内置的类型,比如说int、float64等
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())

Pointer receivers

声明一个指针receiver的method

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 := Vertex3, 4
	v.Scale(10)
	fmt.Println(v.Abs())

  • v.Scale(2)等价于(&v).Scale(2),Go会将第一种自动翻译为第二种
  • 选择指针receiver可以更加高效,避免复制参数,便于修改数值。

Interfaces

  • 一个接口类型定义为一系列method signatures的集合,可以理解将一系列方法定位为同一个名称,根据receiver不同来区分。
package main

import(
	"fmt"
	"math"
)

type Abser interface
	Abs() float64


func main()
	var a Abser
	f := MyFloat(-math.Sqrt2)
	v := Vertex3, 4
	//a = f
	a = &v
	//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)

Interfaces are implemented implicitly

  • 接口隐式实现,一个类型通过实现接口中的方法来实现接口,没有“implements”这种关键字。隐式接口将定义冲实现当中解耦,不需要预先安排就能出现在任何package中
package main

import "fmt"

type I interface 
	M()


type T struct 
	S string


// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() 
	fmt.Println(t.S)


func main() 
	var i I = T"hello"//用T类型实现接口I
	i.M()

  • 接口可以被认为成值和接口的元组(value, type)
  • 对应类型用接口中对应类型的方法,nil值的receiver也能调用对应类型的方法
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)

  • 直接用没有指定类型的接口,会产生超时错误,因为没有类型来指定要调用哪个具体的方法
package main

import "fmt"

type I interface 
	M()


func main() 
	var i I
	describe(i)
	i.M()


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

//结果
(<nil>, <nil>)
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x482161]

goroutine 1 [running]:
main.main()
	/tmp/sandbox957396350/prog.go:12 +0x61

The Empty interface

  • 没有方法的接口是空接口:interface
  • 一个空接口可以接收任何的类型的值,主要用于处理不确定类型的值
package main

import(
	"fmt"
	"math"
)

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)

//结果
(<nil>, <nil>)
(42, int)
(hello, string)

Type assertions

  • 类型断言:t := i.(T),如果接口i基础值包含类型T,那么t就保存对应的类型的值。如果不包含就会引起一个panic
  • 测试是否接口值包含一个具体的值,一个类型断言可以返回两个值:基础值和一个布尔值,布尔值保存断言是否成功(True or False) t, ok := i.(T),此时如果断言不成功也不会产生panic。
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) // panic
	fmt.Println(f)

Stringers

最常见的接口之一是fmt包定义的Stringer。

type Stringer interface 
    String() string

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)


IP转化的练习

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.

func (ip IPAddr)String() string
	return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[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)
	

Errors

error也是一个内置的接口,也是在fmt包中,函数经常返回一个error值

type error interface 
    Error() string

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",
	 //返回值格为MyError结构,出现错误的时候调用NyError类型的Error()函数


func main() 
	if err := run(); err != nil 
		fmt.Println(err)
	

Readers

  • io package指定了io.Reader接口。
  • Read Method:func (T) Read(b []byte) (n int, err error)
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
		
	


Image

image package定义了Image接口
package image

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

package main

import (
	"fmt"
	"image"
)

func main() 
	m := image.NewRGBA(image.Rect(0, 0, 100, 100))
	fmt.Println(m.Bounds())
	fmt.Println(m.At(0, 0).RGBA())

以上是关于Go语言基础的主要内容,如果未能解决你的问题,请参考以下文章

重学Golang系列: 深入理解 interface和reflect

Go进阶详解接口 interface

Go语言基础之结构体

9.Go语言基础之结构体

Go语言学习之旅--接口

Go语言学习之旅--接口