Go 语言基础| 青训营笔记

81 阅读7分钟

1

1.1 特点

  1. 高性能高并发
  2. 语法简单
  3. 丰富标准库
  4. 完善的工具链
  5. 静态链接
  6. 快速编译
  7. 跨平台
  8. 垃圾回收

go语言(或 Golang)是Google开发的开源编程语言,诞生于2006年1月2日下午15点4分5秒,于2009年11月开源,2012年发布go稳定版。Go语言在多核并发上拥有原生的设计优势,Go语言从底层原生支持并发,无须第三方库、开发者的编程技巧和开发经验。 go是非常年轻的一门语言,它的主要目标是“兼具Python 等动态语言的开发速度和C/C++等编译型语言的性能与安全性” 很多公司,特别是中国的互联网公司,即将或者已经完成了使用 Go 语言改造旧系统的过程。经过 Go 语言重构的系统能使用更少的硬件资源获得更高的并发和I/O吞吐表现。充分挖掘硬件设备的潜力也满足当前精细化运营的市场大环境。 Go语言的并发是基于 goroutine 的,goroutine 类似于线程,但并非线程。可以将 goroutine 理解为一种虚拟线程。Go 语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用CPU性能。开启一个goroutine的消耗非常小(大约2KB的内存),你可以轻松创建数百万个goroutine

自带gc。 静态编译,编译好后,扔服务器直接运行。 简单的思想,没有继承,多态,类等。 丰富的库和详细的开发文档。 语法层支持并发,和拥有同步并发的channel类型,使并发开发变得非常方便。 简洁的语法,提高开发效率,同时提高代码的阅读性和可维护性。 超级简单的交叉编译,仅需更改环境变量。 Go 语言是谷歌 2009 年首次推出并在 2012 年正式发布的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去10多年间软件开发的难度令人沮丧。Google 对 Go 寄予厚望,其设计是让软件充分发挥多核心处理器同步多工的优点,并可解决面向对象程序设计的麻烦。它具有现代的程序语言特色,如垃圾回收,帮助开发者处理琐碎但重要的内存管理问题。Go 的速度也非常快,几乎和 C 或 C++ 程序一样快,且能够快速开发应用程序。

2

2.1 安装

go.dev

2.2 IDE

VsCode

GoLand

2.3 基础语法

2.3.1 hello world

package main

import "fmt"

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

Golang 更明确的数字类型命名,支持 Unicode,支持常用数据结构。

类型长度(字节)默认值说明
bool1false
byte10uint8
rune40Unicode Code Point, int32
int, uint4或8032 或 64 位
int8, uint810-128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint1620-32768 ~ 32767, 0 ~ 65535
int32, uint3240-21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint6480
float3240.0
float6480.0
complex648
complex12816
uintptr4或8以存储指针的 uint32 或 uint64 整数
array值类型
struct值类型
string""UTF-8 字符串
slicenil引用类型
mapnil引用类型
channelnil引用类型
interfacenil接口
functionnil函数

2.3.2 变量

package main

import (
	"fmt"
	"math"
)

func main() {
	//声明变量
	var a = "initial"
	var b, c int = 1, 2
	var d = true
	var e float64
	f := float32(e)
	g := a + "foo"
	fmt.Println(a, b, c, d, e, f)
	fmt.Println(g)
	//声明常量
	const s string = "constant"
	const h = 500000000
	const i = 3e20 / h
	fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

iotago语言的常量计数器,只能在常量的表达式中使用。 iotaconst关键字出现时将被重置为0const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用。

  const (
            n1 = iota //0
            n2        //1
            n3        //2
            n4        //3
        )

2.3.3 if else

package main

import "fmt"

func main() {
	if 7%2 == 0 {
		fmt.Println("7 is even")
	} else {
		fmt.Println("7 is odd")
	}
	if 8%4 == 0 {
		fmt.Println("8 is divisible by 4")
	}
	if num := 9; num < 0 {
		fmt.Println(num, "is negative")
	} else if num < 10 {
		fmt.Println(num, "has 1 digit")
	} else {
		fmt.Println(num, "has multiple digits")
	}
}

2.3.4 for

go没有while或do while

package main

import (
	"fmt"
)

func main() {
	//死循环
	for {
		fmt.Println("loop")
		break
	}
	for j := 7; j < 9; j++ {
		fmt.Println(j)
	}
	for n := 0; n < 5; n++ {
		if n%2 == 0 {
			continue
		}
		fmt.Println(n)
	}
	i := 1
	for i <= 3 {
		fmt.Println(i)
		i = i + 1
	}
}

2.3.5 switch

package main

import (
	"fmt"
	"time"
)

func main() {
	a := 2
	switch a {
	case 1:
		fmt.Println("one")
	case 2:
		fmt.Println("two")
	case 3:
		fmt.Println("three")
	case 4, 5:
		fmt.Println("four or five")
	default:
		fmt.Println("other")
	}
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("before noon")
	default:
		fmt.Println("after noon")
	}
}

case内不用加break 不会顺序执行分支 只会选择其一

2.3.6 Array

package main

import "fmt"

func main() {
	var a [5]int
	a[4] = 100
	fmt.Println(a[4], len(a))

	b := [5]int{1, 2, 3, 4, 5}
	fmt.Println(b)

	var twoD [2][3]int
	for i := 0; i < 2; i++ {
		for j := 0; j < 3; j++ {
			twoD[i][j] = i + j
		}
	}
	fmt.Println("twoD: ", twoD)
}

2.3.7 Slice(切片)

package main

import "fmt"

func main() {
    //创建切片
	s := make([]string, 3)
	s[0] = "a"
	s[1] = "b"
	s[2] = "c"
	fmt.Println("get:", s[2])
	fmt.Println("len:", len(s))

	s = append(s, "d")
	s = append(s, "e", "f")
	fmt.Println(s)

	c := make([]string, len(s))
	copy(c, s)
	fmt.Println(c)
	
    //包括前者 不包括后者
	fmt.Println(s[2:5])// c d e
	fmt.Println(s[:5])// a b c d e
	fmt.Println(s[2:])// c d e f

	good := []string{"g", "o", "o", "d"}
	fmt.Println(good)
}

2.3.8 Map

go中map内容顺序是完全随机得

package main

import "fmt"

func main() {
	m := make(map[string]int)
	m["one"] = 1
	m["two"] = 2
	fmt.Println(m)
	fmt.Println(len(m))   // 2
	fmt.Println(m["one"]) // 1
	fmt.Println(m["two"]) // 2
	fmt.Println(m["aaa"]) // 0
	// r为m[key]赋的变量
	// ok可以检测key值是否存在
	r, ok := m["unknown"]
	fmt.Println(r, ok) // 0 false

	delete(m, "one")

	m2 := map[string]int{
		"one": 1,
		"two": 2,
	}
	var m3 = map[string]int{
		"one": 1,
		"two": 2,
	}
	fmt.Println(m2, m3)
}

2.3.9 Range

package main

import "fmt"

func main() {
	nums := []int{2, 3, 4}
	sum := 0
	// 相当于java得for-each循环 for(type elem : elems)
	// for index,elem := range elems
	for i, num := range nums {
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num) //index:0 num:2
		}
	}
	fmt.Println(sum) // 9

	m := map[string]string{
		"a": "A",
		"b": "B",
	}
	// for key,value := range elems
	for k, v := range m {
		fmt.Println(k, v)
	}
	// for key := range elems
	for k := range m {
		fmt.Println("key:", k)
	}
}

2.3.10 Function

package main

import "fmt"

// 不存在一般方法多态
// 用接口实现多态
// func name(elem type,...) returnType{return}
func add(a int, b int) int {
	return a + b
}
func add2(a, b int) int {
	return a + b
}

// func name(elem type,...) (elem type,...){return}
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}
func main() {
	res := add(1, 2)
	fmt.Println(res) // 3

	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // A True

}

2.3.11 Pointer

package main

import "fmt"

// 主要用途是对变量进行修改
func add2(n int) {
	n += 2
}

// 无效
func add2ptr(n *int) {
	*n += 2
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n) // 5
    // 类型匹配
	add2ptr(&n)
	fmt.Println(n) // 7
}

2.3.12 Struct & Struct Function

package main

import "fmt"

type user struct {
	name     string
	password string
}

func checkPassword(u user, pwd string) bool {
	return u.password == pwd
}

func checkPassword2(u *user, pwd string) bool {
	return u.password == pwd
}

// 结构体方法
func (u *user) checkPassword(pwd string) bool {
	return u.password == pwd
}
func (u *user) resetPassword(pwd string) {
	fmt.Println("resetPwd:", pwd)
	u.password = pwd
}

func main() {
	a := user{
		name:     "zhangSan",
		password: "123",
	}
	b := user{
		"qi",
		"132",
	}
	c := user{
		name: "wang",
	}
	c.password = "333"
	var d user
	d.name = "we"
	d.password = "222"

	fmt.Println(a, b, c, d)
	fmt.Println(checkPassword(a, "haha"))
	fmt.Println(checkPassword2(&a, "1222"))
	// 结构体方法
	a.resetPassword("1222")
	fmt.Println(a.checkPassword("1222"))

}

2.3.13 Error

package main

import (
	"errors"
	"fmt"
)

type user struct {
	name     string
	password string
}

func findUser(users []user, name string) (v *user, err error) {
	for _, u := range users {
		if u.name == name {
			return &u, nil
		}
	}
	// 错误描述字段应小写
	return nil, errors.New("not found user")
}

func main() {
	users := []user{
		{
			"wang",
			"1211",
		},
		{
			"eeee",
			"n123",
		},
	}

	u, err := findUser(users, "wang")
    
    // error是否存在
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name)

	//if actioned; conditions{}
	if u, err := findUser(users, "a"); err != nil {
		fmt.Println(err) // not found user
		return
	} else {
		fmt.Println(u.name)
	}
}

2.3.14 Strings & Strings Formatting

package main

import (
	"fmt"
	"strings"
)

type point struct {
	x, y int
}

func main() {
	//	字符串操作
	a := "hello"
	fmt.Println(a)
	fmt.Println(strings.Contains(a, "ll"))                // true
	fmt.Println(strings.Count(a, "l"))                    // 2
	fmt.Println(strings.HasPrefix(a, "he"))               // true
	fmt.Println(strings.HasSuffix(a, "ll"))               // false
	fmt.Println(strings.HasSuffix(a, "lo"))               // true
	fmt.Println(strings.Index(a, "ll"))                   // ll
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
	fmt.Println(strings.Repeat(a, 2))                     // hellohello
	fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
	fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
	fmt.Println(strings.ToLower(a))                       // hello
	fmt.Println(strings.ToUpper(a))                       // HELLO
	fmt.Println(len(a))

	b := "你好"
	fmt.Println(len(b)) // 6

	//	字符串格式化
	s := "hello"
	n := 123
	p := point{1, 2}
	fmt.Println(s, n) //	hello 123
	fmt.Println(p)    //	{1,2}

    // %v任意类型
	fmt.Printf("s=%v\n", s)  //	s=hello
	fmt.Printf("n=%v\n", n)  //	n=123
	fmt.Printf("p=%v\n", p)  //	p={1,2}
	fmt.Printf("p=%+v\n", p) //	p={x:1,y:2}
	fmt.Printf("p=%#v\n", p) //	p=main.point{x:1,y:2}

	f := 3.141592653
	fmt.Println(f)          //	3.141592653
	fmt.Printf("%.2f\n", f) //	3.14
}

2.3.15 JSON

package main

import (
	"encoding/json"
	"fmt"
)

type userInfo struct {
	Name  string
	Age   int `json:"age"` // json中小写输出
	Hobby []string
}

func main() {
	a := userInfo{
		Name: "zhang",
		Age:  18,
		Hobby: []string{
			"go",
			"c",
		},
	}
	buf, err := json.Marshal(a)
	if err != nil {
		// 终止
		panic(err)
	}
	fmt.Println(buf)         // {123 34 78 97...}
	fmt.Println(string(buf)) // {"key":"value"} 无缩进

	buf, err = json.MarshalIndent(a, "", "\t")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf)) // 有缩进的

	var b userInfo
	err = json.Unmarshal(buf, &b) // 复制
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", b)
}

2.3.16 Time

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	fmt.Println(now)
	t1 := time.Date(2022, 3, 23, 11, 23, 42, 0, time.UTC)
	t2 := time.Date(2022, 3, 20, 11, 1, 42, 0, time.UTC)
	fmt.Println(t1)
	fmt.Println(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute())
	fmt.Println(t1.Format("2006-01-02 15:04:05"))
	// 时间差
	diff := t2.Sub(t1)
	fmt.Println(diff)
	fmt.Println(diff.Minutes(), diff.Seconds())
	t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-23 11:23:42")
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t1) // true
	fmt.Println(now.Unix())
}

2.3.17 StringToNum

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 解析字符串为数字
	// (字符串,进制[0为自动推测],位数)
	f, _ := strconv.ParseFloat("1.234", 64)
	fmt.Println(f) // 1.234

	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n) // 111

	n, _ = strconv.ParseInt("0x111", 0, 64)
	fmt.Println(n) // 4096

	// 十进制字符串快速转数字
	n2, _ := strconv.Atoi("123")
	fmt.Println(n2) // 123
	// 输入不合法
	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax

}

2.3.18 Process

package main

import (
	"fmt"
	"os"
	"os/exec"
)

func main() {
	fmt.Println(os.Args)
	fmt.Println(os.Getenv("PATH")) //	进程路径
	fmt.Println(os.Setenv("AA", "BB"))

	buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))
}