Go语言基础语法笔记

110 阅读11分钟

基础语法

引言

本篇笔记记录了Go语言的基础语法和需要注意的点,并加入了自己的总结和思考。

hello world

这部分需要掌握导入package,导入fmt以及Println输出。 需要特别注意引号后面跟着的是(),而非花括号,不要打错。

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

运行

run

这里可以通过 go run main.go进行运行。

build

还可以通过 go build main.go,随后./main运行。

变量介绍

Golang中的变量主要通过var来定义。zai 赋值时的操作可以有=或者:= 。需要注意在goland编辑器中,变量如果定义但未被使用,会报错。

字符串的拼接:用+号。

数据类型的位置放在变量名后面,如

var x float64
var a,b int = 0,1

常量介绍

常量通过const定义,例如

const s string = "ByteDance"

math包介绍

通过在import处导入"math"进行使用。这里介绍一个函数和一个常量。

fmt.Println(math.Sin(math.Pi / 2))

if-else语句

if后面的条件无需写括号。

if i:=1; i > 0 {  
    fmt.Println("positive")  
}else if i < 0 {  
    fmt.Println("negative")  
}else{  
    fmt.Println("zero")  
}

for循环

像之前的语言一样,有break,continue语句,for后面的条件不带圆括号。初始值,结束条件,步进如果都不写就是死循环。

for n := 0; n < 5; n++ {  
    if n%2 == 0 {  
        continue  
    }  
    fmt.Println(n)  
}

switch语句

image.png

  1. 这里需要注意,如果a的值既不是1、2、3,也不是4、5,则会执行default分支,打印 "other"。
  2. 注意每个case后面不需要添加break语句,Go的switch语句默认会在匹配到一个分支后自动终止。

数组

  1. 定义时注意数据类型后置,如var a [5]int。数组中未显式赋值的元素将会是其类型的零值。
  2. 数组的长度用len(a)获取。数组索引是从0开始的,所以第n个元素的索引是n-1。数组的长度是在定义时指定的,长度不可更改。数组的元素在创建后默认会被初始化为其类型的零值。如果没有显式为数组的元素赋值,它们将是零值(对于整数是0,对于字符串是空字符串,对于布尔类型是false,等等)。
  3. 可以创建多维数组,例如二维数组。注意二维数组的定义和赋值方式,以及循环遍历二维数组的方法。
  4. 当访问数组元素时,一定要确保不超出数组的索引范围,否则会导致运行时错误。
  5. 数组和切片的区别。它们都是用于存储一系列元素的数据结构,但是切片具有动态大小,而数组的大小是固定的。数组通常用于有固定数量元素的场景,而切片在需要动态增长元素数量时更为常见。

切片

可以类比python中的切片,冒号左右左闭右开。

  1. 创建。使用make函数创建一个长度为3的字符串切片s ,即s := make([]string, 3)

还可以使用字面值创建一个字符串切片good,内容为[g o o d] good := []string{"g", "o", "o", "d"} 2. 切片的动态增长。切片具有动态增长的能力。通过append函数可以在切片的末尾添加新元素。 3. 切片与数组。切片是围绕动态数组的引用,可以动态增长。数组的长度是固定的,不可更改。 4. 切片操作。切片支持类似数组的索引访问,同时也支持切片操作。切片操作可以获取切片的子切片。 5. 切片复制。切片通过共享底层数组来节省内存,但有时我们需要复制切片内容到一个新的切片,以避免共享底层数组。这时候需要通过copy(s,t)函数。 6. 字面值切片。切片字面值是一种简便的创建切片的方法,使用一组花括号{}表示,并在括号中指定切片的元素值。 7. 切片长度与容量。切片有一个长度和容量的概念,长度表示切片中元素的个数,容量表示底层数组中可容纳的元素个数。当切片的长度等于容量时,再进行append操作会导致创建新的底层数组。

map键值对

  1. map的创建和初始化. 使用make函数可以创建一个空的map。也可以使用map字面值直接创建并初始化map。
  2. map的操作。 map是一种键值对的无序集合。可以使用键名对map进行索引和操作。
  3. map的长度。 使用len函数可以获取map中键值对的数量。
  4. map元素的增删查改。 使用map[key]的方式可以访问map中指定键名的值,使用delete函数可以删除map中指定的键值对。
  5. map的键值对遍历。 Go语言中可以使用range关键字遍历map中的所有键值对。
  6. map的零值。 如果map中不存在指定的键名,那么访问该键名将得到其值类型的零值。
  7. map的存在判断。 使用第二个返回值来判断是否存在某个键名,如果存在,第二个返回值为true,否则为false
  8. map的无序性。 map是无序的,遍历map的键值对时,得到的顺序可能是随机的。
  9. map的初始化。 在声明并初始化一个map时,可以使用map[key]value{}的方式初始化键值对。也可以先声明map变量,再使用make函数分配空间。

range

range用于迭代切片、数组、字符串、映射等数据结构。在每次迭代中,range会返回当前元素的索引(对于切片和数组)或键名(对于映射),以及对应的值。

  1. 切片和数组迭代: 使用for i, val := range sliceOrArray来遍历切片或数组,i是索引,val是当前元素的值。
  2. 映射迭代: 使用for key, val := range mapVar来遍历映射,key是键名,val是对应的值。
  3. 仅迭代键名: 如果只需要键名而不需要对应的值,可以使用for key := range mapVar形式的迭代。
  4. 注意映射的无序性: 映射是无序的,所以迭代结果可能是随机的。
  5. 不使用索引或值: 如果不需要使用索引或值,可以使用下划线(_)来忽略它们,避免产生不必要的变量。

函数

诸如如下的定义形式,其中,形参内容也可简写为(a, b int)

func add(a int, b int) int { return a + b }

还可以这样定义:

func exists(m map[string]string, k string) (v string, ok bool) { v, ok = m[k] return v, ok }

这里定义了一个名为exists的函数,接受一个映射m和一个键名k作为参数。 函数的返回值是映射m中键名k对应的值v和是否存在该键名的布尔值ok。

指针

可以类比C语言中的指针。按值传递和按引用传递: 在Go语言中,函数参数的传递方式有两种:按值传递(pass by value)和按引用传递(pass by reference)。 按值传递: 当参数按值传递时,函数内对参数的修改不会影响原始值。理解为拷贝了一份一样的给函数,与原先的无关。 按引用传递: 当参数按引用传递时,函数内对参数的修改会直接影响原始值。修改的就是原先的。

结构体

结构体定义

举例,定义一个名为user的结构体,表示用户信息

type user struct { 
    name string 
    password string 
}

可以使用多种方式创建结构体变量,包括通过字段名赋值、直接初始化字段值或逐个初始化字段。可以通过点号(.)来访问结构体的字段,如u.password,表示访问结构体upassword字段。使用指针接收者可以在函数中修改接收者指向的结构体,而非指针接收者只能在函数内部操作结构体的副本。

结构体方法

// 定义了一个名为checkPassword的方法,接收者为user类型 
// 这个方法用于检查接收者u的password字段是否等于传入的密码,并返回检查结果 
func (u user) checkPassword(password string) bool { 
    return u.password == password 
} 
// 定义了一个名为resetPassword的方法,接收者为user类型的指针 
// 这个方法用于将接收者u的password字段重置为传入的密码 
func (u *user) resetPassword(password string) { 
    u.password = password 
}

错误处理

需要import "errors",并在函数中声明func findUser(users []user, name string) (v *user, err error)

字符串

字符串操作

使用需要import "strings"

  1. len()获取长度
  2. 字符串连接: 使用Join函数可以将字符串切片连接成一个新的字符串,连接符在第二个参数中指定。
  3. 字符串重复: 使用Repeat函数可以将一个字符串重复多次,重复次数在第二个参数中指定。
  4. 字符串替换: 使用Replace函数可以将字符串中的某个子串替换为另一个字符串。最后一个参数为替换的次数,传入-1表示替换所有匹配项。
  5. 字符串分割: 使用Split函数可以将一个字符串按照指定的分隔符分割为字符串切片。
  6. 字符串大小写转换: 使用ToLowerToUpper函数可以将字符串转换为小写和大写。

格式化

"fmt"包就是用于格式化的包。

  1. 格式化输出: 使用Printf函数可以对字符串、整数、浮点数和结构体等进行格式化输出。格式化时,可以使用占位符%v来表示默认格式。
  2. 格式化整数: 使用%v占位符可以直接输出整数的值。
  3. 格式化浮点数: 使用%.2f占位符可以控制浮点数输出的小数位数,这里保留两位小数。
  4. 格式化结构体: 使用%v占位符可以按默认格式输出结构体的字段值,使用%+v占位符会打印字段名,使用%#v占位符会输出Go语法表示的值

JSON

需要import "encoding/json"

  1. JSON编码。 使用json.Marshal函数可以将Go语言的数据结构转换为JSON格式的字节切片。
  2. 解码。 使用json.Unmarshal函数可以将JSON格式的字节切片解码为Go语言的数据结构。
  3. 格式化输出。使用json.MarshalIndent函数可以编码为带缩进格式的JSON字符串,使得JSON数据更易读。

时间处理

需要import time包。

  1. 获取当前时间. 使用time.Now()函数可以获取当前的时间对象now
  2. 指定时间对象。 使用time.Date()函数可以根据年、月、日、时、分、秒、纳秒和时区创建一个指定时间的时间对象。
  3. 格式化输出时间。 使用Format()方法可以将时间对象格式化成指定的字符串形式。
  4. 时间差计算。 使用Sub()方法可以计算两个时间对象之间的时间差,得到一个Duration类型的结果,可以用来获取分钟、秒数等。
  5. 字符串解析为时间。 使用time.Parse()函数可以将指定格式的字符串解析为时间对象。
  6. Unix时间戳。 使用Unix()方法可以获取时间对象的Unix时间戳,表示自UTC时间的1970年1月1日起经过的秒数

数字解析

  1. 字符串转换为float64. 使用strconv.ParseFloat函数可以将字符串转换为float64类型。第二个参数为解析精度,通常设为64。
  2. 字符串转换为int64。 使用strconv.ParseInt函数可以将字符串转换为int64类型。第二个参数表示字符串中的数字使用的进制,10表示十进制。第三个参数表示结果类型,通常设为64位整数。
  3. 字符串转换为int。 使用strconv.Atoi函数可以将字符串转换为int类型。
  4. 错误处理。 strconv.Atoistrconv.ParseInt等函数在转换失败时会返回一个错误,我们可以使用多返回值的方式来处理这个错误。

进程

  1. 命令行参数。 使用os.Args变量可以获取命令行参数,包括执行的程序名和传递的参数。
  2. 环境变量。 使用os.Getenv()函数可以获取指定的环境变量的值。使用os.Setenv()函数可以设置环境变量。
  3. 执行外部命令。 使用exec.Command()函数可以创建一个执行外部命令的对象。然后使用CombinedOutput()方法可以执行命令并获取其标准输出和标准错误合并后的结果。
  4. 错误处理。 在执行外部命令时,如果命令出错,exec.Command()会返回一个非nil的错误对象。我们可以通过检查错误来处理执行命令的结果。

分析总结

在学习了上述基础知识后,持续的实践和项目经验在巩固方面比较重要。