Go语言基础| 青训营笔记

136 阅读6分钟

前言

有一定的C++基础,写过一些数据结构和算法,力扣刷过一些题。Python研究生阶段有自学,帮别人改模型和跑模型。没有接触过Go语言。

1.1 Go特性

高性能、高并发;语法简单、学习曲线平缓(一周?);丰富的标准库(类似Python?);完善的工具链;静态链接(编译到一个可执行文件?);快速编译;跨平台(还可以开发安卓、IOS);垃圾回收(new、delete?)

字节最开始居然使用Python写的...

2 Go配置环境

2.1 安装Golang

go.dev/

2.2 IDE(Vscode)

平常用的是Vscode,所以尝试着在vscode上配置go,参考的是这篇博客:GO开发环境配置_go环境配置_astrolabium的博客-CSDN博客

中间遇到了两个问题: 1.安装go tools碰到了失败,参考: 解决VSCode安装Go tools失败的问题 - 知乎 (zhihu.com) 2.配置完后,运行hello,world程序时,出现错误:hello.go:1:1: expected 'package', found 'EOF' 解决:运行前要保存文件,GO文件在运行前一定要按Ctrl+s保存吗?

尝试了所有程序员的第一个程序(梦回17年):

package main

import "fmt"

func main() {
    fmt.Println("Hello World go!")
}

package main:表示主程序?

fmt:类似于Python那些包,GO也是需要导入很多包的,但是与Python不同的是: Python导入不需要的包的时候不会报错,GO会报错。

func main() : 类似C++ int main(), 主程序代码所在

3 本节课代码

在历时两个小时的看课加一遍写代码,把这节课听完了,着实有点耗时间。

image.png

看的这节课类似于看了“菜鸟教程”似的,基本就是把所有的用法直接罗列一遍,不过也确实学到了很多Go的用法,也真切的体会到了,Go很多与C++和Python的相同和不同之处吧。

package main

import "fmt"

type point struct {
	x, y int
}

func main() {
	s := "hello"
	n := 123
	p := point{1, 2}
	fmt.Println(s, n)
	fmt.Println(p)

	fmt.Printf("s=%v\n", s) // printf 类似于C语言的输出, %v 指的就是后面的数值
	fmt.Printf("n=%v\n", n) // 无论什么类型,都会把其中存的数值输出出来
	fmt.Printf("p=%v\n", p)
	fmt.Printf("p=%+v\n", p) // %+v , 就会输出字段的名字和值
	fmt.Printf("p=%#v\n", p) // %#v, 打印的更详细

	f := 3.1415926
	fmt.Println(f)
	fmt.Printf("%.2f\n", f) // 可以使用%.2f输出只保留两位小数

}
package main

import "fmt"

func main() {
	i := 1
	for { // 死循环
		fmt.Println("loop")
		i++
		if i == 10 {
			break
		}
	}
	for j := 1; j < 9; j++ {
		if j%2 == 0 {
			continue
		}
		if j == 8 {
			break
		}
		fmt.Println(j)
	}
	// while i < 19 { // 没有 while循环

	// }

}

package main

import "fmt"

func main() { // map是完全无序的,遍历是不会按照插入顺序输出,是偏随机的
	m := make(map[string]int) // 定义方式
	m["one"] = 1
	m["two"] = 2
	fmt.Println(m)
	fmt.Println(len(m))
	fmt.Println(m["one"])

	r, ok := m["unknow"] // ok 用来判断相应的key是否存在
	fmt.Println(r, ok)

	delete(m, "one")

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

package main

import (
	"fmt"
	"strconv" // 字符串和数字之间的转换
)

func main() {
	f, _ := strconv.ParseFloat("1.234", 64) // 解析一个字符串
	fmt.Println(f)
	n, _ := strconv.ParseInt("111", 10, 64) // 解析一个字符串, 10 表示进制, 64位精度
	fmt.Println(n)

	n, _ = strconv.ParseInt("0x1000", 0, 64) // 0 表示自动推测
	fmt.Println(n)

	n2, _ := strconv.Atoi("123") // 快速把一个十进制字符串转换成一个数字
	fmt.Println(n2)

	n2, err := strconv.Atoi("AAA") // 不合法会返回一个err
	fmt.Println(n2, err)
}

package main

import "fmt"

func add2(n int) { // 与C++相同, 传入时是copy了一个新的变量,对之前的变量无法做到更改
	n += 2
}

func add2ptr(n *int) { // 指针定义, *int 后置
	*n += 2
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n)
	add2ptr(&n) // 与C++一致, 传入地址
	fmt.Println(n)
}

package main

import "fmt"

func main() {
	s := make([]string, 3) // 初始默认了长度3
	s[0] = "0"
	s[1] = "1"
	s[2] = "2"
	fmt.Println("get :", s[2])
	fmt.Println("len :", len(s))

	s = append(s, "d") // 类似Python 有append用法
	s = append(s, "e", "f")
	fmt.Println(s)

	c := make([]string, len(s))
	copy(c, s)
	fmt.Println(c)

	fmt.Println(s[2:5]) // 类似Python
	fmt.Println(s[:5])
	// fmt.Println(s[2:-1]) // 有问题, 和Python不同了 -1 不指最后一位
	fmt.Println(s[2:])

	good := []string{"g", "o", "o", "d"} // 没初始长度
	fmt.Println(good)
}

package main

import "fmt"

type user struct {
	name     string
	password string
}

func (u user) checkPassword(password string) bool { // 结构体成员函数,定义方法
	return u.password == password
}

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

func main() {
	a := user{name: "wang", password: "1024"} // 结构体的几种定义方法
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	fmt.Println(a, b, c, d)
	fmt.Println(a.checkPassword("1023")) // 用的时候就可以使用 "." 来使用了
	fmt.Println(b.checkPassword2("1024"))
	fmt.Println(c.checkPassword("1111"))
	fmt.Println(d.checkPassword2("1024"))
}

package main

import "fmt"

type user struct { // 后置有点太不习惯了
	name     string
	password string
}

func main() {
	a := user{name: "wang", password: "1024"} // 结构体的几种定义方法
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	fmt.Println(a, b, c, d)
	fmt.Println(checkPassword(a, "haha"))
	fmt.Println(checkPassword2(&a, "1024"))
}

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

func checkPassword2(u *user, password string) bool { // 结构体做参数的时候也可以是指针
	return u.password == password
}
package main

import (
	"fmt"
	"time"
)

func main() {
	a := 2
	switch a {
	case 1: // 不用写break,默认不继续执行
		fmt.Println("one")
	case 2:
		fmt.Println("tow")
	case 3:
		fmt.Println("three")
	case 4, 5: // 可以这样用...
		fmt.Println("four or five")
	default:
		fmt.Println("default")
	}

	t := time.Now() // 访问系统时间
	switch {        // 还可以不用写变量
	case t.Hour() < 12:
		fmt.Println("It's before noon")
	default:
		fmt.Println("It's after noon")
	}
}

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) // 赋值e

	g := a + "foo"

	fmt.Println(a, b, c, d, e, f, g) // g 如果没有被使用也会出现报错,跟Python不同

	const s string = "constant" // 没有确定类型,根据上下文确定
	const h = 50000000
	const i = 3e20 / h
	fmt.Println(s, h, i, math.Sin(h), math.Sin(i)) // math包可以提供一些基本函数
}

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

func main() {
	u, err := findUser([]user{{"wang", "1024"}}, "wang")
	if err != nil { // 有error
		fmt.Println(err)
		return
	}
	fmt.Println(u.name) // 或者返回值

	if u, err := findUser([]user{{"wang", "1024"}}, "zhang"); err != nil {
		fmt.Println(err)
		return
	} else {
		fmt.Println(u.name)
	}
}

4.总结

  1. 个人感觉Go相较于C++ 和 Python还是有着很多的不同之处的,感觉学过C++ 和 Python的对于第一节课而言还是比较容易入门的。
  2. 在学习Go的时候,类型后置确实很不习惯,不太清楚为什么选择这个方式,学习C++ 前置类型不是挺好的吗?
  3. Go里的一个错误处理方式还不错,函数可以直接返回一些错误信息,可以直接print错误信息。
  4. 类似于Python, Go有很多功能强大的包,可以方便的调用很多函数,可以沟通进程等,我也只是在Python中连接过数据库做过实验,之前也没在C++和Python中试过和进程相关的代码,还是比较新奇的。