这是我参与「第五届青训营 」笔记创作活动的第1天
一. 基础结构
package main
- 此文件属于main包的一部分,main包是程序的入口包,此文件也就是程序的入口文件
import (
"fmt"
)
- 导入标准库中的“format”包(用于字符串的 IO 和格式化)
go run foldername/filename.go
// or
go build foldername/filename.go
./filename.go
- 运行go文件
graph LR
Package --> import --> func
二. 基础语法
- 强类型语言:可以修改变量定义的类型
- 字符串是内置类型,可以直接用
+进行拼接,用==比较两个字符串 const常量没有确定的类型,根据使用的上下文自动确定类型,对应的是var的定义(常用:=)
- 字符串是内置类型,可以直接用
- 循环:没有
while和do-while循环,只有for循环 - 分支(条件):
if-else—— if 后的条件没有( )小括号限制,内容必有大括号{ }switch—— 不用加break截断分支,找到数值并做输出后,自动跳出分支;可以使用任意变量类型,比如字符串、结构体;可以取代任意的if-else语句
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
- 数组:具有编号且长度固定的元素**序列,真实情况很少用数组,更多用切片(可变长度,任意时刻更改长度),**可以像数组一样往其中写或存储值,用append追加元素,扩容需要重新赋值
// 扩容
s = append(s, "plus")
// 拷贝
c := make([]string, len(s))
copy(c, s)
fmt.Println(c)
// 像python一样的切片操作(左闭右开),但不支持负数的处理,需要用len取出长度,再做简单运算、
fmt.Println(s[2:5])
- map(哈希或字典):使用最频繁的数据结构,完全无序,不会按照字母和插入顺序输出,偏随机顺序
// 用make创建一个空map —— key和value [KV 键值对]
m := make(map[string]int)
m["one"] = 1 // 创建KV
delete(m, "one") // 删除KV
// ok查看KV是否存在
r, ok := m["unknown"]
fmt.Println(r, ok)
- 对于一个
slice or map可以用range快速遍历
// 对于数组:i 可以 替换为 _ ,实现索引遍历的过滤
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
// 对于map,k和v任选
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v)
}
for k := range m {
fmt.Println("key", k)
}
- 函数
- 定义参数的变量类型后置
- 原生支持返回多个值,一般两部分(真正返回结果;错误信息)
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) // A True
- 指针:比较初级,主要针对参数修改
package main
import "fmt"
// Copy版本,无法修改实际值
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
}
- 结构体:带类型的字段的集合
- 用结构体的名称初始化所定义的变量
- 没有初始化就是空值:数值就是0,字符串是空字符串
- 可以作为函数的参数,再加上指针定义,就可以直接对结构体进行修改,也可以减少大结构体拷贝的开销
- 为结构体定义方法,相对于类成员函数
// 从一个普通函数,改造成结构体方法(类成员函数)
func (u user) checkPassword(password string) bool {
return u.password == password
}
// 也可以带指针,修改结构体内变量的值
func (u *user) resetPassword(password string) {
u.password = password
}
- 字符串:strings包有很多快捷接口可以调用
Printf: 格式化的%v可以代替C的%d, %s等各种具体类型 (\n同样负责换行;+, #more detailed)
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
-
JSON 处理:保证已有结构体每个字段名称都是大写,就可以用
json.Marshal()序列化成一个数组,本质是字符串(用string()强制类型转换才能打印出字符串,否则打印出16进制编码)- 序列化后,还可以反序列化到一个空的变量
-
时间处理:
- 在和某些系统交互的时候,经常用到时间戳,需要使用
Unix() 2006-01-02 15:04:05是固定时间格式的表达,内容固定
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
fmt.Println(now.Unix()) // 1648738080
- 字符串和数字的转化
- 字符串
- 进制
- 位数(精度)
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
// 进制处为0时自动判断进制
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
// 相当于ParseInt("123",10,0)
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
// Itoa 实现十进制转化为字符串,没有error
n3 := strconv.Itoa(12)
fmt.Println(n3)
fmt.Printf("%T, %v\n", n3, n3)
- 进程信息
import (
"fmt"
"os"
"os/exec"
)
// go run example/20-env/main.go a b c d
// 获取进程在执行时的一些命令行参数, 临时目录(自生文件名)
fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
// 获取环境变量
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
// 写入环境变量
fmt.Println(os.Setenv("AA", "BB"))
三. 小结
语法简洁,和python大部分逻辑很相似
标准库效率优化,而且error和panic异常处理分明,代码易读,提高开发和迭代效率