FreezeJ' Blog

GO基础代码

2022-03-08

最近看了一下GO语言,学习一下。记录一下基础代码块,方便查阅。
参考教程:
https://www.runoob.com/go
http://c.biancheng.net/golang

变量声明

package main

import "fmt"

// 多行声明
var (
	a int
	b bool
	c = "123"
)

func main() {
	x := 1
	fmt.Println(x)
	test := "test"
	fmt.Println(test)
	var x1, x2, x3 = "1", "2", "3"
	fmt.Println(x1, x2, x3)
	y1, y2, y3 := "4", "5", "6" // 这种不带声明的只能出现在函数体
	fmt.Println(y1, y2, y3)
	fmt.Println(a, b, c)
	/*
		在Go中,声明的变量必须使用,否则不能通过编译。
		下划线"_"在Go中表示一个空白标识符,它是一个只写变量,可以把不需要的变量赋值给它。
	*/
	_, a := 1, 2
	fmt.Println(a)
}

变量打印

package main

import "fmt"

func main() {
	var test string = "test" // string变量类型可以省略,编译器会根据所赋的值来识别
	fmt.Println(test)

	var x, y int = 1, 2
	fmt.Println(x, y)
}

变量空值

package main

import "fmt"

func main() {
	var varInt int
	var varStr string
	var varFloat64 float64
	var varBool bool
	var varList []int
	fmt.Println(varInt, varStr, varFloat64, varBool, varList)
}

类型转换

package main

import (
	"fmt"
	"reflect"
	"strconv"
)

func main() {
	a := 123
	b := float32(a)
	// 数字转字符串
	c := strconv.Itoa(a)
	// 字符串转数字
	d, _ := strconv.Atoi(c)
	e, _ := strconv.ParseInt(c, 10, 64)
	fmt.Println(reflect.TypeOf(a), a)
	fmt.Println(reflect.TypeOf(b), b)
	fmt.Println(reflect.TypeOf(c), c)
	fmt.Println(reflect.TypeOf(d), d)
	fmt.Println(reflect.TypeOf(e), e)
}

常量

package main

import "fmt"

// 用作枚举
const (
	Unknown = 0
	Female  = 1
	Male    = 2
)

// 常量是一个简单值的标识符,在程序运行时,不会被修改的量
func main() {
	const a = "test"      // string类型,使用双引号
	const b = 'A'         // char类型,使用单引号
	const c, d = '1', '2' // 常量可以声明定义,并且不使用
	fmt.Println(a)
	fmt.Println(b) // 打印的是ASCII码

	// iota常量索引,每次 const 出现时,都会让 iota 初始化为0
	const x = iota // x=0
	const (        // 出现const,iota初始化为0
		y = iota //y=0
		z        //z=1   相当于z=iota
	)
}

数组

package main

import "fmt"

func printGroup(group []int) { // 这里接收参数的类型必须和定义时一样
	fmt.Println("数组长度:", len(group))
	for i := range group {
		fmt.Println(i)
	}
}

// 与Python的数组不同,GO语言中的数组长度不可改变
func main() {
	group1 := [5]int{1, 2, 3} // 不足元素补充空值
	fmt.Println(group1)
	group1[3] = 4 // 赋值
	fmt.Println(group1)
	group2 := []int{1, 2, 3}       // 不定长度使用...,编译器自动计算长度
	group3 := []int{1, 2, 3, 4, 5} // 不定长度使用...,编译器自动计算长度
	printGroup(group2)
	printGroup(group3)
}

切片slice

package main

import "fmt"

// slice相当于动态数组
func main() {
	var s []int   // 未指定长度的数组其实就是切片
	if s == nil { // 判断空切片
		fmt.Println("空切片:", s)
	}
	s = make([]int, 10, 20) // 数组长度10,容量20
	fmt.Println("初始化切片:", s)
	for i, _ := range s {
		s[i] = i
	}
	fmt.Println("切片循环赋值:", s)
	fmt.Println("切片截取:")
	fmt.Println(s[2:5])
	fmt.Println(s[:5])
	fmt.Println(s[5:])
	fmt.Println(s[5 : len(s)-2]) // 好像没有直接s[5:-2]的写法
	fmt.Println(s)
	fmt.Println("cap容量:", cap(s))
	fmt.Println("len长度:", len(s))
	for i := 0; i < 50; i++ {
		// 如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
		s = append(s, 10+i) // 插入元素
	}
	fmt.Println(s)
	fmt.Println("cap容量:", cap(s)) // 容量不足时会自动扩容,但是容量和长度不是同等的计算方式
	fmt.Println("len长度:", len(s))

	// 拷贝切片,目标在前
	var n []int
	n = make([]int, 10, 20)
	copy(n, s)
	fmt.Println("拷贝的切片n:", n)
	copy(n, []int{0, 0, 0, 0, 0})
	fmt.Println("拷贝的切片n:", n)
	fmt.Println("拷贝的切片s:", s)

	// 删除元素
	slice1 := []int{1, 2, 3, 4, 5}
	fmt.Println(slice1)
	// 删除第一个元素
	slice2 := slice1[1:]
	fmt.Println(slice2)
	// 删除最后一个元素
	slice3 := slice1[:len(slice1)-1]
	fmt.Println(slice3)
	// 删除第x个元素(n<=len)
	x := 2
	slice4 := append(slice1[:x-1], slice1[x:]...)
	fmt.Println(slice4)
}

range

package main

import "fmt"

// range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
func main() {
	// 遍历数组
	numArr := [...]int{1, 2, 3}
	var sum int
	for index, num := range numArr {
		fmt.Printf("第%d个数字是:%d\n", index+1, num)
		sum += num
	}
	fmt.Println("sum:", sum)

	// 遍历切片,循环10次
	count := 0
	for range make([]int, 10) {
		fmt.Println(count)
		count++
	}

	// 遍历字符串
	for _, c := range "hello world" {
		fmt.Println(c)
	}
}

map

package main

import "fmt"

func main() {
	// 声明一个map,key为string类型,value也是string类型
	weekMap := map[string]string{
		"Mon":  "星期一",
		"Tues": "星期二",
		"Wen":  "星期三",
		"Thur": "星期四",
		"Fri":  "星期五",
		"Sat":  "星期六",
		"Sun":  "星期天",
	}
	fmt.Println(weekMap)
	fmt.Println(weekMap["Mon"])
	// 删除元素
	delete(weekMap, "Sun")
	fmt.Println(weekMap)
	// 插入元素
	weekMap["Sun"] = "星期天"
	fmt.Println(weekMap)
}

并发map

package main

import (
	"fmt"
	"sync"
)

func main() {
	syncMap := sync.Map{}
	// 存储值
	syncMap.Store("test1", 1)
	// 可以储存不同的类型
	syncMap.Store("test2", "2")

	// 读取值
	fmt.Println(syncMap.Load("test1"))
	fmt.Println(syncMap.Load("test2"))

	// 遍历
	syncMap.Range(func(key, value interface{}) bool {
		fmt.Println(key)
		fmt.Println(value)
		return true // 返回false就不继续循环
	})
}

指针

package main

import "fmt"

func swapPoint(a, b *int) {
	var tmp int
	tmp = *a
	*a = *b
	*b = tmp
}

func main() {
	a := 10
	var ip *int
	fmt.Println("空指针:", ip)
	ip = &a
	fmt.Println("a的值:", a)
	fmt.Println("a的地址:", &a)
	fmt.Println("ip的值:", ip)
	fmt.Println("ip的指向:", *ip)

	// 指针数组
	const MAX = 3
	arr := [MAX]int{1, 2, 3}
	var ptr [MAX]*int
	for i := 0; i < MAX; i++ {
		ptr[i] = &arr[i]
	}
	fmt.Println("指针数组的值:", ptr)
	for i := range ptr {
		fmt.Println("指向的值:", i)
	}

	// 指向指针的指针
	var v int
	var vptr *int
	var vpptr **int
	v = 300
	vptr = &v
	vpptr = &vptr
	fmt.Println("v的值", v)
	fmt.Println("ptr的值", *vptr)
	fmt.Println("pptr的值", **vpptr)

	// 向函数传递指针
	x1, x2 := 1, 9
	var ptr1, ptr2 *int
	ptr1 = &x1
	ptr2 = &x2
	fmt.Println(x1, x2)
	swapPoint(ptr1, ptr2)
	fmt.Println(x1, x2)
}

结构体

package main

import "fmt"

type Books struct {
	name   string
	author string
	pages  uint8
}

func (b Books) print() {
	fmt.Printf("书本名称: %s\n作者: %s\n页码: %d\n", b.name, b.author, b.pages)
}

func main() {
	b1 := Books{
		name:   "Hello",
		author: "FreezeJ",
		pages:  80,
	}
	b2 := Books{
		name:   "World",
		author: "FreezeJ",
		pages:  38,
	}
	b1.print()
	b2.print()

	// 结构体指针
	var bp1, bp2 *Books
	bp1, bp2 = &b1, &b2
	// 地址
	fmt.Println(bp1)
	fmt.Println(bp2)
	// 值
	fmt.Println(*bp1)
	fmt.Println(*bp2)
	// 引用内容
	fmt.Println(bp1.name)
	fmt.Println(b1.name)
	fmt.Println(bp2.name)
	fmt.Println(b2.name)
}

switch

package main

import (
	"fmt"
	"strconv"
)

const (
	Mon  = "Monday"
	Tues = "Tuesday"
	Wen  = "Wednesday"
	Thur = "Thursday"
	Fri  = "Friday"
	Sat  = "Saturday"
	Sun  = "Sunday"
)

func main() {
	var day string
	fmt.Println("请输入:")
	fmt.Scanf("%s", &day)

	// 形式一
	switch day {
	case Mon:
		fmt.Println("星期一")
	case Tues:
		fmt.Println("星期二")
	case Wen:
		fmt.Println("星期三")
	case Thur:
		fmt.Println("星期四")
	case Fri:
		fmt.Println("星期五")
	case Sat:
		fmt.Println("星期六")
	case Sun:
		fmt.Println("星期天")
	default:
		fmt.Println("日期错误")
		return
	}

	// 形式二,类似于使用if...else...
	switch {
	case day == Sat, day == Sun:
		fmt.Println("周末")
	default:
		fmt.Println("要上班")
	}

	// fallthrough关键字,使用后case匹配不跳出,继续执行下一个case
	leftDay := 0
	switch day {
	case Mon:
		leftDay++
		fallthrough
	case Tues:
		leftDay++
		fallthrough
	case Wen:
		leftDay++
		fallthrough
	case Thur:
		leftDay++
		fallthrough
	case Fri:
		leftDay++
	}
	if leftDay > 0 {
		fmt.Println("还有" + strconv.Itoa(leftDay) + "天放假!")
	}
}

if语句

package main

import "fmt"

func main() {
	var value int
	fmt.Scan(&value) // 输入数字
	if value > 1 {
		fmt.Println("大于1")
	} else if value > 999 {
		fmt.Println("大于999")
	} else {
		fmt.Println("小于或等于1")
	}
}

循环

package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i <= 10; i++ {
		sum += i
	}
	fmt.Println(sum)

	// 类似于while
	count := 1
	for count < 10 {
		fmt.Printf("计数器:%d\n", count)
		count += 1
	}

	// for each 形式
	strings := []string{"google", "baidu", "bing"}
	for i, x := range strings {
		fmt.Println(i, x)
	}

	// 嵌套循环:九九乘法表
	for x := 1; x < 10; x++ {
		for y := 1; y <= x; y++ {
			z := x * y
			fmt.Printf("%d*%d=%d ", x, y, z)
		}
		fmt.Println("")
	}

	// break语句
	fmt.Println("等于5时跳出:")
	for i := 0; true; i++ {
		fmt.Printf("%d\n", i)
		if i == 5 {
			break
		}
	}

	// continue语句
	fmt.Println("10以内的单数:")
	for i := 0; i < 10; i++ {
		if i%2 == 0 {
			continue
		}
		fmt.Printf("%d\n", i)
	}

	// goto语句
	n := 1
AddN:
	n++
	if n < 10 {
		goto AddN
	} else {
		fmt.Println(n)
	}
}

函数

package main

import "fmt"

// 数字乘以2
func double(i int) int {
	return 2 * i
}

func swap(a *int, b *int) {
	fmt.Println("a的内存地址:", a)
	fmt.Println("a的值:", *a)
	fmt.Println("b的内存地址:", b)
	fmt.Println("b的值:", *b)
	var c int
	c = *b
	*b = *a
	*a = c
	fmt.Println("a的内存地址:", a)
	fmt.Println("a的值:", *a)
	fmt.Println("b的内存地址:", b)
	fmt.Println("b的值:", *b)
}

func hello() {
	fmt.Println("hello!")
}

func doSomething(data string, work func(string)) {
	work(data)
}

// 可变参数
func myFunc(args ...string) {
	for _, arg := range args {
		fmt.Println(arg)
	}
}

func main() {
	x, y, z := 2, 6, 3
	fmt.Println("x, y, z:")
	fmt.Printf("%d %d %d\n", x, y, z)
	// 函数返回值
	fmt.Println("double x, y, z:")
	fmt.Printf("%d %d %d\n", double(x), double(y), double(z))

	// 使用引用修改值
	a, b := 33, 44
	fmt.Println("交换前", a, b)
	swap(&a, &b)
	fmt.Println("交换后", a, b)

	// 函数保存为变量
	var h func()
	h = hello
	h()

	// 匿名函数声明并调用
	func(data string) {
		fmt.Println("hello!", data)
	}("world")

	// 匿名函数保存为变量
	f := func() {
		fmt.Println("good!")
	}
	f() // 调用匿名函数

	// 匿名函数用作回调函数
	doSomething("test", func(data string) {
		fmt.Println(data)
	})

	// 可变参数
	myFunc("1", "2", "3")
	strArray := []string{"4", "5", "6"}
	myFunc(strArray...)
}

接口

package main

import "fmt"

type Phone interface {
	call()
}

type IOS struct {
	version int
}

func (ios IOS) call() {
	fmt.Println("IOS version:", ios.version)
}

type Android struct {
	version int
}

func (android Android) call() {
	fmt.Println("Android version:", android.version)
}

func main() {
	var p1 Phone
	var p2 Phone
	p1 = IOS{version: 15}
	p2 = Android{version: 14}
	p1.call()
	p2.call()
}

错误处理

package main

import (
	"fmt"
)

// DIV_ERR 自定义错误信息结构
type DIV_ERR struct {
	etype int // 错误类型
	v1    int // 记录下出错时的除数、被除数
	v2    int
}

// 实现接口方法 error.Error()
func (div_err DIV_ERR) Error() string {
	if 0 == div_err.etype {
		return "除零错误"
	} else {
		return "其他未知错误"
	}
}

// 除法
func div(a int, b int) (int, *DIV_ERR) {
	if b == 0 {
		// 返回错误信息
		return 0, &DIV_ERR{0, a, b}
	} else {
		// 返回正确的商
		return a / b, nil
	}
}
func main() {
	// 正确调用
	v, r := div(100, 2)
	if nil != r {
		fmt.Println("(1)fail:", r)
	} else {
		fmt.Println("(1)succeed:", v)
	}
	// 错误调用
	v, r = div(100, 0)
	if nil != r {
		fmt.Println("(2)fail:", r)
	} else {
		fmt.Println("(2)succeed:", v)
	}
}

panic和recover

package main

import "fmt"

// 任何崩溃都表明了我们的代码中可能存在漏洞,所以对于大部分漏洞,我们应该使用Go语言提供的错误机制,而不是 panic。

func testPanic() {
	defer func() {
		err := recover()
		if err != nil {
			fmt.Println("recover")
			fmt.Println(err)
		}
	}()
	fmt.Println("start")
	panic("raise panic")
	fmt.Println("end")
}

func main() {
	testPanic()
}

并发

package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 数据生产者
func producer(header string, channel chan<- string) {
	// 无限循环, 不停地生产数据
	for {
		// 将随机数和字符串格式化为字符串发送给通道
		channel <- fmt.Sprintf("%s: %v", header, rand.Int31())
		// 等待1秒
		time.Sleep(time.Second)
	}
}

// 数据消费者
func customer(channel <-chan string) {
	// 不停地获取数据
	for {
		// 从通道中取出数据, 此处会阻塞直到信道中返回数据
		message := <-channel
		// 打印数据
		fmt.Println(message)
	}
}
func main() {
	// 创建一个字符串类型的通道
	channel := make(chan string)
	// 创建producer()函数的并发goroutine
	go producer("cat", channel)
	go producer("dog", channel)
	// 数据消费函数
	customer(channel)
}
标签: GO
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏