Golang入门

该文内容整理自Go指南

基本结构

若变量名以大写字母开头则为导出的, 函数外的每个语句都必须以关键词(var, func…)开始

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello world")
}

函数

func swap(x, y string) (string, string) {
    return y, x
}

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

//函数值
func compute(fn func(float64, float64) float64) float64 {
    return fn(3, 4)
}

hypot := func(x, y float64) float64 {
    return x*x + y*y
}

//函数闭包, 即引用了函数体之外变量的函数值
func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

pos, neg := adder(), adder()

// defer语句会将函数推迟到外层函数返回之后执行
func main() {
    defer fmt.Println("world")
    fmt.Println("hello")
}

变量/常量/指针

var i, j int = 1, 2
var c, python = true, "no"
k := 3 // 仅能在函数内使用
const Pi = 3.14

var (
    ToBe bool       = false
    MaxInt uint64 = 1<<64 - 1
)

i = 42
p := &i
*p = 21

循环与分支

// Go仅有for循环
for i := 0; i < 10; i++ {

}

for ; sum < 1000; {

}

for sum < 1000 {

}

// 无限循环
for {

}

// 与for一样,if可以在条件表达式之前执行一个简单的语句
if v := math.Pow(x, n); v < lim {

} else {

}

switch os := runtime.GOOS; os {
    case "darwin":
        // ...
    case "linux":
        // ...
    default:
        // ...
}

结构体

type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
    v := Vertex{1, 2}
    p := &v
    p.X = 1e9 //自动转换为(*p).X

    v2 = &Vertex{2, 3} //创建并返回指针
}

数组

var a [2]string
primes := [6]int {1,2,3,4,5,6}
var s []int = primes[1 : 4] //半开区间, 且为引用
q := []int {1,2,3}
s := []struct {
     i int
} {
    {1},
    {2}
}

len(a) //获取数组长度
cap(a) //获取数组容量

a := make([]int, 5)     //len(a)=5, cap(a)=5
b := make([]int, 0, 5) //len(a)=0, cap(a)=5

board := [][]string {
    []string{"_", "_"},
    []string{" ", "_"}
}
board[0][0] = "X"

var s []int
s = append(s, 1,2,3,4)

// for range 第一个值为下标,第二个值为元素的副本, 可以用_替代
for i, v := range s {
    fmt.Printf(i, v)
}

映射

var m map[string]Vertex

m = make(map[string]Vertex)
m["Bell Labs"] = Vertex {
    40, -74
}

var c = map[string]Vertex {
    "Bell Labs": Vertex {
        40, -74
    },
    "Google": Vertex {
        37, -122
    }
}

delete(m, "Google")
v, ok := m["Google"] // 不存在此键则ok为false, v为零值

方法

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

v := Vertex{3, 4}
v.Abs()

// 可以为非结构体类型声明方法
type MyFloat float64

func (f MyFloat) Abs() float64 {
    //...    
}

f := MyFloat(2)
f.Abs()

// 指针接收者能够更改接收者指向的指,值接收者则是对副本进行操作
func (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}

接口

type Abser interface {
    Abs() float64
}

//接口类型的变量可以保存任何实现了这些方法的值
var a Abser

// 类型通过实现一个接口的所有方法来实现该接口,
// 因此无需专门显示声明,也就没有implements关键字

type I interface {
    M()
}

type T struct {
    S string
}

func (t T) M() {
    //...
}

func main() {
    var i I = T{"hello"}
    i.M()
}

// 空接口能够保存任何类型的值,因为每个类型都至少实现了零个方法
var i interface{}
i = 42
i = "hello"

// fmt包中定义的Stringer是最普遍的接口之一
type Stringer interface {
    String() string
}

func (p Person) String() string {
    //...
}

a := Person {42}
fmt.Println(a)

类型断言

var i interface {} = "hello"

s, ok := i.(string) //断言接口值i保存了具体类型string, 并将值赋予变量s, 同时由ok判断是否断言成功

f := i.(float64) // 将产生panic

类型选择

// 与类型断言相似,但具体类型被替换成了关键字type
func do(i interface{}) {
	switch v := i.(type) {
	case int:
		fmt.Printf("Twice %v is %v\n", v, v*2)
	case string:
		fmt.Printf("%q is %v bytes long\n", v, len(v))
	default:
		fmt.Printf("I don't know about type %T!\n", v)
	}
}

错误

// Go使用error值来表示错误状态, 且error是一个内建接口
type error interface {
    Error() string
}

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

Goroutine

go f(x, y, z) //启动一个新的goroutine

// 信道通过 <- 来发送或接收值
// 默认情况下,发送和接收操作在另一端准备好之前
// 都会阻塞,因此goroutine可以在没有显示的锁情况下进行同步

func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum // 将和送入 c
}

func main() {
	s := []int{7, 2, 8, -9, 4, 0}

	c := make(chan int)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x, y := <-c, <-c // 从 c 中接收

	fmt.Println(x, y, x+y)
}

// 信道可以带缓冲,仅当信道的缓冲区填满后,
// 向其发送数据时才会阻塞,当缓冲区为空时,
// 接收方会阻塞
ch := make(chan int, 2)


// 发送者可以通过close关闭一个信道来表示没有需要发送的值了
// 接收者可以测试信道是否被关闭
// 若没有值可以接收且信道已被关闭,则ok为false
v, ok := <-ch

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
    // 不断从信道接收值,直到c被关闭
	for i := range c {
		fmt.Println(i)
	}
}

// 只有发送者才能关闭信道,同时信道在通常情况下无需关闭,
// 只有在必须告诉接收者不再有需要发送的值时才有必要关闭,
// 例如终止range循环

// select语句使得一个goroutine能够等待多个通信操作
// 阻塞到某个分支可以继续执行为止,当多个分支都准备
// 好时会随机选择一个执行。同时当其他分支都没准备好,
// default分支就会执行

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
        default:
            //...
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
}

sync.Mutex

import (
	"fmt"
	"sync"
	"time"
)

type SafeCounter struct {
	v   map[string]int
	mux sync.Mutex
}

func (c *SafeCounter) Inc(key string) {
	c.mux.Lock()
	c.v[key]++
	c.mux.Unlock()
}

func (c *SafeCounter) Value(key string) int {
	c.mux.Lock()
	defer c.mux.Unlock()
	return c.v[key]
}

func main() {
	c := SafeCounter{v: make(map[string]int)}
	for i := 0; i < 1000; i++ {
		go c.Inc("somekey")
	}

	time.Sleep(time.Second)
	fmt.Println(c.Value("somekey"))
}

Related post

  1. linux文件系统

    2020-11-27

  2. SpringBoot+WebSocket

    2020-10-27

  3. Memory Network

    2020-07-27

  4. hadoop框架概述

    2021-09-17

There are no comment yet.

COMMENT

Take a Coffee Break

Recommend post

  1. 常用工具指令

    2022-09-18

Category list

ABOUT

Welcome to FullStar, a captivating online destination where the realms of software development and personal reflections intertwine.

April 2025
M T W T F S S
 123456
78910111213
14151617181920
21222324252627
282930  

Life Logs

  1. 回首

    2023-07-14

Return Top