前言:Go 的一些必备知识

1. Go 语言命名

Go的函数、变量、常量、自定义类型、包(package)的命名方式遵循以下规则:

  1. 首字符可以是任意的Unicode字符或者下划线
  2. 剩余字符可以是Unicode字符、下划线、数字
  3. 字符长度不限

Go 语言代码风格及开发事项

  • 代码每一行结束后不用写分号

  • 推荐使用驼峰式命名

  • Go 编译器是一行一行进行编译的,因此我们一行就写一条语句,不能把多条语句写在一起

  • Go 定义的变量 或 import 的包如果没有用到,代码不能编译通过

  • 左括号必须紧接着语句不换行

    func main() {fmt.Println("Hello Go")
    } 
    

2. Go 关键字

Go 一共有 25 个关键字

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

37 个保留字

Constants:    true  false  iota  nilTypes:    int  int8  int16  int32  int64  uint  uint8  uint16  uint32  uint64  uintptrfloat32  float64  complex128  complex64bool  byte  rune  string  errorFunctions:   make  len  cap  new  append  copy  close  deletecomplex  real  imagpanic  recover

3. Go 语言声明

有四种主要的声明方式

var(声明变量), const(声明常量), type(声明类型) ,func(声明函数)

Go的程序是保存在多个.go文件中,文件的第一行就是 package XXX 声明,用来说明该文件属于哪个包(package),package声明下来就是 import 声明,再下来是类型,变量,常量,函数的声明。

可见性

  1. 声明在函数内部,是函数的本地值,类似private
  2. 声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值,类似protect
  3. 声明在函数外部且首字母大写是所有包可见的全局值,类似public

4. Printf 和 Println 的区别

这个其实和 Java 有点像, Print 不自动换行,而 Println 会自动换行

还有就是变量输出的方法,如下:

func main(){a:=10b:=20fmt.Println("a=",a, "b=",b)	// a= 10 b= 20fmt.Printf("a=%d, b=%d", a, b) // a=10, b=20
}

5. Init 和 main 函数

在 Go 语言中,init() 函数和 main() 函数是程序执行的两个关键入口点,它们有明确的执行顺序和作用:

举个例子

func init() {fmt.Println("imp-init1()")
}func init() {fmt.Println("imp-ini2()")
}func main() {fmt.Println("main()")
}// 输出
imp-init1()
imp-ini2()
main()

init() 函数特点

  • 自动执行:无需显式调用,在程序启动时自动运行。
  • 包级别:每个包(包括依赖包)都可以包含一个或多个 init() 函数。
  • 执行顺序
    1. 按包的依赖关系递归执行(先执行导入包的 init())。
    2. 同一包中,按文件名的字典序执行不同文件中的 init()
    3. 同一文件中,按代码中出现的顺序执行多个 init()
  • 用途
    • 初始化包级变量(尤其是复杂初始化)。
    • 注册操作(如数据库驱动、插件)。
    • 执行一次性配置(如读取配置文件)。
  • 无参数无返回值func init() { ... }

② main 函数特点

  • 程序入口main 包中的 main() 是唯一程序入口。
  • 执行时机:在所有依赖包的 init() 完成后执行。
  • 唯一性:整个程序只能有一个 main() 函数(位于 package main)。
  • 无参数无返回值func main() { ... }

关键区别

特性init() 函数main() 函数
所在包任意包(包括依赖包)必须在 main
数量每个包可有多个 init()整个程序仅一个 main()
调用方式自动执行自动执行(程序入口)
执行顺序在导入的包初始化后、main()在所有 init() 完成后执行
典型用途初始化包级状态、注册操作主程序逻辑入口

注意事项

  1. 避免滥用 init()
    • 复杂的初始化逻辑应封装成显式函数调用,而非全放在 init() 中。
    • 防止隐式依赖导致代码难以追踪。
  2. 慎用全局状态init() 中初始化的包级变量相当于全局状态,可能引发并发问题。
  3. 错误处理init() 中发生错误通常通过 panic 终止程序,需谨慎处理(如配置文件不存在)。
  4. 明确初始化顺序:当多个包有相互依赖的 init() 时,需确保执行顺序符合预期(通过调整导入顺序)。

一、Go 工具链

Go 提供了强大而完整的命令行工具链,让开发者能够高效地开发、测试、构建和部署 Go 应用程序。

1. 核心命令概览

$ go
Go is a tool for managing Go source code.Usage:go command [arguments]The commands are:build       compile packages and dependenciesclean       remove object filesdoc         show documentation for package or symbolenv         print Go environment informationbug         start a bug reportfix         run go tool fix on packagesfmt         run gofmt on package sourcesgenerate    generate Go files by processing sourceget         download and install packages and dependenciesinstall     compile and install packages and dependencieslist        list packagesrun         compile and run Go programtest        test packagestool        run specified go toolversion     print Go versionvet         run go tool vet on packagesUse "go help [command]" for more information about a command.Additional help topics:c           calling between Go and Cbuildmode   description of build modesfiletype    file typesgopath      GOPATH environment variableenvironment environment variablesimportpath  import path syntaxpackages    description of package liststestflag    description of testing flagstestfunc    description of testing functionsUse "go help [topic]" for more information about that topic.
  • go env:用于打印Go语言的环境信息。
  • go run:编译并运行命令源码文件。
  • go get:根据要求和实际情况从互联网上下载或更新指定的代码包及其依赖包,并对它们进行编译和安装。
  • go build:用于编译我们指定的源码文件或代码包以及它们的依赖包。
  • go install:编译并安装指定的代码包及它们的依赖包。
  • go clean:删除掉执行其它命令时产生的一些文件和目录。
  • go doc:可以打印附于Go语言程序实体上的文档。我们可以通过把程序实体的标识符作为该命令的参数来达到查看其文档的目的。
  • go test:用于对Go语言编写的程序进行测试。
  • go list:列出指定的代码包的信息。
  • go fix:把指定代码包的所有Go语言源码文件中的旧版本代码修正为新版本的代码。
  • go fmt:格式化代码
  • go vet:是一个用于检查Go语言源码中静态错误的简单工具。
  • go tool:工具集。
  • go mod:模块管理

2. 举例说明

① go run —— 编译运行

go run main.go # 运行单个文件
go run main.go utils.go # 运行多个文件
go run . # 运行当前包的所有 .go 文件
go run main.go arg1 arg2 # 传递参数给程序

② go fmt —— 代码格式化

// 格式化前
package main
import "fmt"
func main() {fmt.Println("Hello");fmt.Println("World")
}// 格式化后 (go fmt)
package mainimport "fmt"func main() {fmt.Println("Hello")fmt.Println("World")
} 

③ go test —— 运行测试

go test # 运行当前目录所有测试
go test ./package # 运行指定包的测试
go test -v # 显示详细测试信息
go test -cover # 运行覆盖率测试# 生成覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out

比如

// math_test.go
package mathimport "testing"func TestAdd(t *testing.T) {result := Add(2, 3)if result != 5 {t.Errorf("Add(2, 3) = %d; want 5", result)}
}func BenchmarkAdd(b *testing.B) {for i := 0; i < b.N; i++ {Add(2, 3)}
}// 运行测试
go test -v
// 运行基准测试
go test -bench=.

④ go vet —— 代码静态分析

go vet # 分析当前包
go vet github.com/user/project # 分析指定包
go vet -v # 显示详细信息

⑤ go tool —— 工具集

go tool pprof # 性能分析工具
go tool cover # 覆盖率工具
go tool nm # 符号表查看
go tool objdump # 反汇编
go tool link # 链接器

⑥ go mod —— 模块管理

go mod init module_name # 初始化新模块
go mod tidy # 添加依赖
go mod graph # 查看依赖图
go mod verify # 验证依赖
go mod download # 下载依赖
go mod why package_name # 查看模块信息# 具体操作
# 1. 创建新项目
mkdir myproject && cd myproject
go mod init github.com/user/myproject
# 2. 添加外部依赖
go get github.com/gin-gonic/gin
# 3. 整理依赖
go mod tidy

3. 完整开发流程

# 1. 初始化项目
mkdir myapp && cd myapp
go mod init github.com/user/myapp# 2. 编写代码
# 创建 main.go 文件# 3. 快速测试运行
go run main.go# 4. 格式化代码
go fmt ./...# 5. 静态分析
go vet# 6. 编写测试
# 创建 *_test.go 文件# 7. 运行测试
go test -v# 8. 构建可执行文件
go build -o myapp main.go# 9. 安装到系统
go install

组合命令

# 一键格式化、分析、测试
go fmt ./... && go vet ./... && go test ./...

跨平台编译

GOOS=linux GOARCH=amd64 go build main.go # 编译 Linux 版本
GOOS=windows GOARCH=amd64 go build main.go # 编译 Windows 版本
GOOS=darwin GOARCH=amd64 go build main.go # 编译 macOS 版本

性能优化编译

go build -ldflags "-s -w" main.go # 优化编译
go build -ldflags "-X main.version=1.0.0" main.go# 指定版本信息

二、基础语法

1. 变量 & 常量 申明

变量背景:程序运行过程中的数据都是保存在内存中,我们想要在代码中操作某个数据时就需要去内存上找到这个变量,但是如果我们直接在代码中通过内存地址去操作变量的话,代码的可读性会非常差而且还容易出错,所

1.1 常见的变量定义方式

变量名称命名要求:由 字母、数字、下划线组成,其中首个字符不能为数字,而且 Go 语言中 关键字 和 保留字 都不能用作变量名

Go语言在声明变量的时候,会自动对变量对应的内存区域进行初始化操作。每个变量会被初始化成其类型的默认值,例如: 整型和浮点型变量的默认值为0。 字符串变量的默认值为空字符串。 布尔型变量默认为false。 切片、函数、指针变量的默认为nil

当然我们也可在声明变量的时候为其指定初始值。变量初始化的标准格式如下:

var 变量名 类型 = 表达式

① var 声明和定义变量

var age int
var name string = "zs" // 批量声明
var(email string = "@12.com"phone int = 123flag bool = truenamex = "zs"
)
var a1, a2, a3 string // 这样也可以

② 类型推导 定义变量

有时候我们会将变量的类型省略,这个时候编译器会根据等号右边的值来推导变量的类型完成初始化。

var name = "ls"

③ 短变量声明

在函数内部,可以使用更简略的 := 方式声明并初始化变量。

// 简短声明
:a = 10
:b = 20
  • 注意:短变量 := 只能用于声明局部变量,不能用于全局变量

如下是变量作用域

// 全局变量
var globalVar = "全局变量"func main() {// 局部变量localVar := "局部变量"fmt.Println(globalVar, localVar)// 块级作用域{blockVar := "块级变量"fmt.Println(blockVar)}// fmt.Println(blockVar) // 错误:blockVar 作用域已结束
}

④ 匿名变量

在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示,例如:

func foo() (int, string) {return 10, "Q1mi"
}
func main() {x, _ := foo()_, y := foo()fmt.Println("x=", x)fmt.Println("y=", y)
}

匿名变量 不占用命名空间不会分配内存,所以匿名变量之间不存在重复声明。 (在Lua等编程语言里,匿名变量也被叫做 哑元变量。)

注意事项

  • 函数外的每个语句都必须以关键字开始(var、const、func等)
  • := 不能使用在函数外。
  • _ 多用于占位,表示忽略值。

注意:go 语言中变量定义以后必须要使用,而且同一作用域内不支持重复声明

func main(){var a = "aa" fmt.Println(a) // 不使用就会提示错误
}

补充:下面赋值正确的是:

  • A. var x = nil B. var x interface{} = nil
  • C. var x string = nil D. var x error = nil

参考答案及解析:BD。这道题考的知识点是 nil。nil 只能赋值给指针、chan、func、interface、map 或 slice 类型的变量。强调下 D 选项的 error 类型,它是一种内置接口类型,看它的源码就知道,所以 D 是对的。

1.2 常量声明

相对于变量,常量是恒定不变的值,多用于定义程序运行期间不会改变的那些值。 常量的声明和变量声明非常类似,只是把var换成了const,常量在定义的时候必须赋值。

func main() {// 1. 基本常量声明const pi = 3.14159const maxUsers = 1000// 2. 指定类型常量const version string = "1.0.0"const port int = 8080// 3. 批量声明const (appName = "MyApp"appVersion = "2.0"debugMode = true)fmt.Println(pi, maxUsers, version)
}
  • 注意:常量定义之后必须要赋值,不能先声明再赋值

const同时声明多个常量时,如果省略了值则表示和上面一行的值相同。 例如:

const (n1 = 100n2n3
)

上面示例中,常量n1、n2、n3的值都是100

1.3 const 常量结合 iota 使用

iota 是 Go 语言的常量计数器,只能在常量的表达式中使用(否则会出现 编译错误)

  • iota 在 const 关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次
  • iota 可理解为 const 语句块的行索引,使用iota能简化定义,在定义枚举时很有用。

举个例子

// 自增长
const (Monday = iota    // 0Tuesday          // 1Wednesday        // 2Thursday 		 // 3Friday           // 4Saturday         // 5Sunday           // 6
)

常见的 iota 示例

① 使用 _ 跳过某些值

const (n1 = iota //0n2        //1_n4        //3
)

iota 声明中间插队

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

③ 带步长的 iota

const (A = iota * 10    // 0B                // 10C                // 20D                // 30
)//这里的<<表示左移操作,1<<10表示将1的二进制表示向左移10位,也就是由1变成了10000000000,也就是十进制的1024。同理2<<2表示将2的二进制表示向左移2位,也就是由10变成了1000,也就是十进制的8。
const (_  = iotaKB = 1 << (10 * iota)MB = 1 << (10 * iota)GB = 1 << (10 * iota)TB = 1 << (10 * iota)PB = 1 << (10 * iota)
)

④ 多个 iota 定义在一行

const (a, b = iota + 1, iota + 2 //1,2c, d                      //2,3e, f                      //3,4
)

2. 数据类型

Go 预言者的数据类型一般分为两种:

  • 基本数据类型:整型、浮点型、布尔型、字符串
  • 复合数据类型:数组、切片、结构体、函数、map、通道(channel)、接口

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.1 基本数据类型

整型可以分为下面两个大类

  • 有符号整型按长度分为:int8、int16、int32、int64
  • 对应的无符号整型:uint8、uint16、uint32、uint64

特殊整型

  • uint:32 位操作系统上就是 uint32,64 位操作系统上就是 uint64
  • int:32 位操作系统上就是 int32,64 位操作系统上就是 int64
  • uintptr:无符号整型, 用于存放一个指针

可以通过 unsafe.Sizeof() 查看不同长度的整型在内存中的存储空间

浮点型

Go 语言支持两种浮点型数: float32 | float64,这两种浮点型数据格式遵循 IEEE 754 标准。

  • float32 浮点数的最大范围位 3.4e38,可用常量定义为: math.MaxFloat32
  • float32 浮点数的最大范围位 1.8e308,可用常量定义为: math.MaxFloat64

Go 中 float 精度丢失问题

func main() {var f float64 = 1129.6fmt.Println(f * 100)	// 112959.99999999999
}
  • 而且 减法的时候也会出现这种问题,一般来说可以引入第三方包来调用相关方法来解决

举例说明

func main() {// 整数类型var a int = 42           // 根据平台决定大小var b int8 = 127         // 8位整数 (-128 to 127)var c int16 = 32767      // 16位整数var d int32 = 2147483647 // 32位整数var e int64 = 9223372036854775807 // 64位整数var f uint = 42          // 无符号整数var g uint8 = 255        // 8位无符号整数var h uint16 = 65535     // 16位无符号整数// 浮点数类型var i float32 = 3.14     // 32位浮点数var j float64 = 3.141592653589793 // 64位浮点数(默认)// bool 类型 -- 默认值为 falsevar flag = true// 复数类型var k complex64 = 1 + 2ivar l complex128 = 3 + 4i// 字节和别名var m byte = 'A'         // uint8 的别名var n rune = '中'        // int32 的别名,表示 Unicode 码点fmt.Printf("整数: %d %d %d %d %d\n", a, b, c, d, e)fmt.Println("int 字节大小: " unsafe.Sizeof(a))	// 8fmt.Printf("无符号: %d %d %d\n", f, g, h)fmt.Printf("浮点数: %.2f %.6f\n", i, j)fmt.Printf("复数: %v %v\n", k, l)	// 复数: (1+2i) (3+4i)fmt.Printf("字符: %c %c\n", m, n)
}
2.2 字符串类型

字符串转义符

转义符含义
\r回车符(返回行首)
\n换行符(直接跳到下一行同列位置)
\t制表符
\'单引号
\"双引号
\\反斜杠

字符串 常用操作

  • len(s):求长度

  • + 或者 fmt.Sprintf():拼接字符串

  • strings.Split():分割字符串

  • strings.contains:判断是否包含该子串

  • strings.HasPrefix(), strings.HasSuffix:前缀/后缀 判断

  • strings.Index(), strings.LastIndex():子串出现位置

  • strings.Join(a[]string, sep string):Join 操作

举例说明

func main() {s1 := "goLang"fmt.Printf("%v -- %T\n", s1, s1)// 输出 多行字符串 使用 `s2 := `"Hello"World`fmt.Println(s2)fmt.Println("中文: ", len("你"), "英文: ", len("s")) // 中文:  3 英文:  1// 字符串拼接result := s1 + " " + s2fmt.Println(result)// 字符串遍历for i, char := range s1 {fmt.Printf("索引 %d: %c\n", i, char)}arr := []string{"c++", "java", "go"} // 切片s3 := strings.Join(arr, "-")fmt.Println(s3) // c++-java-go
}
2.3 字符类型

Go 语言的字符有以下两种类型

  1. uint8 类型(byte):代表 ASCII 码的一个字符
  2. rune 类型:代表一个 UTF-8 字符

当需要处理 中文、日文 或 其他复合字符 时候,需用到 rune 类型,rune 类型实际是一个 int32

byte 类型:组成每个字符串的元素叫作 “字符”,可以通过遍历字符串元素获取字符,字符用 '' 包裹起来,比如:

func main(){a := 'a'b := '0'// 直接输出 byte 得到的是这个字符对应码值fmt.Println(a)fmt.Println(b)// 格式化输出 得到这个字符fmt.Printf("%c--%c\n", a, b)// 循环输出字符串字符s := "你好 golang"for i := 0; i < len(s); i++{fmt.Printf("%v(%c) ", s[i], s[i])}
}

上面我们看输出结果会发现 循环输出 中文的时候会出现乱码字符,此时就应该使用 rune 来处理 Unicode

func main() {s := "你好 golang"for _, v := range s {fmt.Printf("%v(%c) ", v, v)}
}

注意:修改字符串需要先将其转成 []rune[]byte,完成后再转为 string,但是无论哪种转换都会重新分配内存,并复制 字节数组

func main() {s := "big"// s[0] = 'p'	// 报错// 复制bs := []byte(s)bs[0] = 'p'fmt.Println(string(bs))
}
2.4 数据类型转换
func main() {// 1. 整型和整型间转换var (a1 int8  = 20a2 int16 = 40)fmt.Println(int16(a1) + a2)// 2. 整型和浮点型转换var f float64 = 20fmt.Println(float64(a1) + f)// 3. 其他类型 -> string (Sprintf)// 注意: Sprintf 使用转换格式 int(%d), float(%f), bool(%t), byte(%c)s := fmt.Sprintf("%d", a1)fmt.Printf("v: %v, type: %T\n", s, s)// 4. 通过 strconv 进行转换var a int = 8s1 := strconv.Itoa(a) // 也可以  := strcinv.FomatInt(a1, 10) // 指定进制fmt.Printf("v: %v, type: %T\n", s1, s1)// folat 转换参数如下:// 参数1: 要转换值 		参数2: 格式化类型 'f'、'b'、'e'、'E'、'g'、'G'// 参数3: 保留小数点 -1(不对小数点格式化)	参数4: 格式化的类型s2 := strconv.FormatFloat(f, 'f', 2, 64)fmt.Printf("v: %v, type: %T\n", s2, s2)
}

注意:go 中 数值类型 无法直接转成 bool 类型,同理 bool 也不能直接转成数值类

2.5 占位符格式

fmt 包实现了格式化 IO 函数,类似于 C 的 printf 和 scanf,格式 占位符 衍生自 C,但比 C 更简单

使用如下

package main
import "fmt"func main() {a := 10fmt.Printf("a=%v, %T", a, a)
}
// 输出: a=10, int

一般

%v	相应值的默认格式, 在打印结构体时, "加号" 标记 (% + v) 会添加字段名
%#v 相应值的 Go 语法表示
%T	相应值的类型的 Go 语法表示
%%  字面上上的百分号, 并非值的占位符

布尔:%t 单词 ture 或 false

整数

%b	二进制表示
%c	相应 Unicode 码点所表示字符
%d	十进制表示
%o	八进制表示
%q	单引号围绕的字符字面值, 由 Go 语法安全的转义
%x  十六进制表示, 字母形式为小写 a-f
%X	十六进制表示, 字母形式为大写 A-F
%U	Unicode格式: U + 1234, 等同于 "U+%04X"

浮点数及其复合构成

%b 无小数部分的、指数为 2 的幂的科学计数法,-123456p-78
%e 	科学计数法,-1234.56e+78
%E 	科学计数法,-1234.56E+78
%f 	有小数点但无指数,123.456
%g	根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出
%G	根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出

3. 运算符 & 控制语句

运算符就那些最基本的,这里就不过过多讲解,直接来看看 控制语句 相关例子

条件语句
Go 的 if 语句表达式外无需小括号 ( ),而大括号 { } 则是必须的

  • 而且if 语句可以在条件表达式前执行一个简短语句,该语句声明的变量作用域仅在 if 之内。
  • 在Go语言中,else必须紧跟在if的右大括号后面,不能换行(即else不能放在下一行的开头,除非前面有右大括号)
func main() {score := 85// 基本 if 语句if score >= 60 {fmt.Println("及格")}// if-else 语句if score >= 90 {fmt.Println("优秀")} else if score >= 80 {fmt.Println("良好")} else if score >= 60 {fmt.Println("及格")} else {fmt.Println("不及格")}// if 中的简短声明if n := len("Hello"); n > 5 {fmt.Println("字符串长度大于5")} else {fmt.Println("字符串长度小于等于5")}// 注意:n 在这里不可访问// fmt.Println(n) // 错误!
}

循环语句

Go 的for 循环 与 if 语句类似,C/C++ 中的While循环相当于Go中的 for 循环

func main() {// 1. 传统 for 循环for i := 0; i < 5; i++ {fmt.Printf("i = %d ", i)}fmt.Println()// 2. while 风格循环j := 0for j < 5 {fmt.Printf("j = %d ", j)j++}fmt.Println()// 3. 无限循环count := 0for {count++if count > 3 {break}fmt.Printf("count = %d ", count)}fmt.Println()// 4. continue 和 breakfor i := 0; i < 10; i++ {if i%2 == 0 {continue // 跳过偶数}if i > 7 {break // 大于7时跳出}fmt.Printf("%d ", i)}fmt.Println()
}

Go 中可以使用 for range 遍历数组、切片、字符串、map 及 通道,通过 for range 遍历的返回值规律如下:

  1. 数组、切片、字符串 返回索引和值
  2. map 返回 键和值
  3. 通道(channel) 只返回通道内的值

例子

func main(){// 1. for range 键值循环(遍历数组、切片、map等)numbers := []int{1, 2, 3, 4, 5}for index, value := range numbers {fmt.Printf("索引 %d: 值 %d\n", index, value)}// 2. 只遍历索引for index := range numbers {fmt.Printf("索引: %d ", index)}fmt.Println()// 3. 只遍历值for _, value := range numbers {fmt.Printf("值: %d ", value)}fmt.Println()
}

分支语句

func main() {grade := "B"// 基本 switchswitch grade {case "A":fmt.Println("优秀")case "B":fmt.Println("良好")case "C":fmt.Println("及格")default:fmt.Println("不及格")}// 多条件 casescore := 85switch {case score >= 90:fmt.Println("优秀")case score >= 80:fmt.Println("良好")case score >= 60:fmt.Println("及格")default:fmt.Println("不及格")}// switch 中的简短声明switch day := "Monday"; day {case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":fmt.Println("工作日")case "Saturday", "Sunday":fmt.Println("周末")}
}
fallthrough

在 Go 语言中,fallthrough 是一个特殊的控制流语句,用于在 switch 语句中强制"穿透"到下一个 case 块。它的主要用途是允许单个匹配条件执行多个 case 块,这在某些特定场景下非常有用。

如下:

switch n := 2; n {
case 1:fmt.Println("Case 1")fallthrough // 强制穿透到下一个 case
case 2:fmt.Println("Case 2")fallthrough // 继续穿透
case 3:fmt.Println("Case 3")
default:fmt.Println("Default case")
}

注意

  • 必须是 case 块的最后一条语句,后面不能有其他语句(编译器会报错)
  • 只能穿透到下一个 case 块,不能穿透到 default 块(如果后面是 default 会执行它)

4. 数组

func main() {// 1. 声明数组var arr1 [5]int                    // 声明长度为5的整数数组var arr2 [3]string = [3]string{"a", "b", "c"} // 声明并初始化arr3 := [4]float64{1.1, 2.2, 3.3, 4.4}        // 类型推导// 2. 自动计算长度arr4 := [...]int{10, 20, 30, 40} // 长度自动计算为4// 3. 访问和修改数组元素fmt.Println("arr1[0]:", arr1[0]) // 默认值为0arr1[0] = 100fmt.Println("修改后 arr1[0]:", arr1[0])// 4. 数组长度fmt.Printf("arr2 长度: %d\n", len(arr2))fmt.Printf("arr3 长度: %d\n", len(arr3))// 5. 遍历数组fmt.Println("遍历 arr4:")for i := 0; i < len(arr4); i++ {fmt.Printf("arr4[%d] = %d ", i, arr4[i])}fmt.Println()// 6. range 遍历fmt.Println("range 遍历 arr3:")for index, value := range arr3 {fmt.Printf("索引 %d: 值 %.1f\n", index, value)}// 7. 数组是值类型(拷贝传递)arr5 := [3]int{1, 2, 3}arr6 := arr5 // 拷贝整个数组arr6[0] = 100fmt.Printf("arr5: %v, arr6: %v\n", arr5, arr6) // arr5 不变// 8. 多维数组var matrix [2][3]int = [2][3]int{{1, 2, 3},{4, 5, 6},}var pos = [2][2] string{{"北京", "上海"},{"广州", "深圳"},}fmt.Println("二维数组:")for i := 0; i < len(matrix); i++ {for j := 0; j < len(matrix[i]); j++ {fmt.Printf("%d ", matrix[i][j])}fmt.Println()}
}

实用示例 1

func main() {// 示例1:数组初始化的不同方式var scores [5]float64scores = [5]float64{95.5, 87.0, 92.5, 88.0, 90.0}// 计算平均分sum := 0.0for _, score := range scores {sum += score}average := sum / float64(len(scores))fmt.Printf("平均分: %.2f\n", average)// 示例2:查找最大值numbers := [...]int{34, 78, 23, 90, 12, 67}max := numbers[0]for _, num := range numbers {if num > max {max = num}}fmt.Printf("数组中的最大值: %d\n", max)
}

实用示例2(值 类型 & 引用类型)

// 数组作为函数参数(值传递)
func modifyArray(arr [3]int) {arr[0] = 100fmt.Println("函数内 arr:", arr)
}// 数组指针作为参数(引用传递)
func modifyArrayPtr(arr *[3]int) {(*arr)[0] = 100fmt.Println("函数内 arr:", *arr)
}func main(){// 数组传递arr := [3]int{1, 2, 3}fmt.Println("调用前 arr:", arr)modifyArray(arr)fmt.Println("调用后 arr:", arr) // 原数组不变modifyArrayPtr(&arr)fmt.Println("指针调用后 arr:", arr) // 原数组改变// 值类型: 数组var a1 = [...]int{1, 2, 3}a2 := a1a1[0] = 11fmt.Println(a1) // 11 2 3fmt.Println(a2) // 1 2 3// 引用类型: 切片var b1 = []int{1, 2, 3}b2 := b1b1[0] = 11fmt.Println(b1) // 11 2 3fmt.Println(b2) // 11 2 3
}

5. 下划线

“_” 是特殊标识符,用来忽略结果

① 下划线在 import 中

在Golang里,import的作用是导入其他package

import 下划线(如:import hello/imp)的作用:当导入一个包时,该包下的文件里所有 init() 函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行 init() 函数而已。

  • 这个时候就可以使用 import 引用该包。即使用【import _ 包路径】只是引用该包,仅仅是为了调用 init() 函数,所以无法通过包名来调用包中的其他函数。

示例

// 代码结构
src 
|
+--- main.go            
|
+--- hello|+--- hello.gopackage mainimport _ "./hello"func main() {// hello.Print() //编译报错:./main.go:6:5: undefined: hello
}// hello.go
package helloimport "fmt"func init() {fmt.Println("imp-init() come here.")
}func Print() {fmt.Println("Hello!")
}

输出结果

imp-init() come here.

② 下划线在代码中

import "os"func main() {buf := make([]byte, 1024)f, _ := os.Open("/Users/***/Desktop/text.txt")defer f.Close()for {n, _ := f.Read(buf)if n == 0 {break    }os.Stdout.Write(buf[:n])}
}

解释1

  • 下划线意思是忽略这个变量
  • 比如 os.Open,返回值为 *os.File,error;普通写法是 f,err := os.Open("xxxxxxx")
  • 如果此时不需要知道返回的错误值,就可以用 f, _ := os.Open("xxxxxx"),如此则忽略了error变量

解释2

  • 占位符,意思是那个位置本应赋给某个值,但是咱们不需要这个值,所以就把该值赋给下划线,意思是丢掉不要。
  • 这样编译器可以更好的优化,任何类型的单个值都可以丢给下划线。
  • 这种情况是占位用的,方法返回两个结果,而你只想要一个结果。那另一个就用 “_” 占位,而如果用变量的话,不使用,编译器是会报错的。

补充

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

第二个import就是不直接使用mysql包,只是执行一下这个包的init函数,把mysql的驱动注册到sql包里,然后程序里就可以使用sql包来访问mysql数据库了。

三、函数初始

我们这里暂时就看一些最基本的函数,后面再来深入

// 最简单的函数
func sayHello() {fmt.Println("Hello, World!")
}// 带参数的函数
func greet(name string) {fmt.Printf("Hello, %s!\n", name)
}// 带返回值的函数
func add(a, b int) int {return a + b
}// 多返回值函数
func divide(a, b float64) (float64, error) {if b == 0 {return 0, fmt.Errorf("除数不能为零")}return a / b, nil
}func main() {sayHello()greet("张三")result := add(3, 5)fmt.Printf("3 + 5 = %d\n", result)quotient, err := divide(10, 2)if err != nil {fmt.Println("错误:", err)} else {fmt.Printf("10 / 2 = %.2f\n", quotient)}
}

内置函数

Go 语言拥有一些不需要进行导入操作就可以使用的内置函数。它们有时可以针对不同的类型进行操作,例如:len、cap 和 append,或必须用于系统级的操作,例如:panic。因此,它们需要直接获得编译器的支持。

  • append :用来追加元素到数组、slice中,返回修改后的数组、slice
  • close:主要用来关闭channel
  • delete:从map中删除key对应的value
  • panic:停止常规的 goroutine (panic和recover:用来做错误处理)
  • recover:允许程序定义goroutine的panic动作
  • imag :返回complex的实部 (complex、real imag:用于创建和操作复数)
  • real:返回complex的虚部
  • make:用来分配内存,返回Type本身(只能应用于slice, map, channel)
  • new:用来分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针
  • cap:capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和 map)
  • copy:用于复制和连接slice,返回复制的数目
  • len:来求长度,比如string、array、slice、map、channel ,返回长度
  • print、println :底层打印函数,在部署环境中建议使用 fmt 包

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90766.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90766.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/90766.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bert项目--新闻标题文本分类

目录 技术细节 1、下载模型 2、config文件 3、BERT 文本分类数据预处理流程 4、对输入文本进行分类 5、计算模型的分类性能指标 6、模型训练 7、基于BERT的文本分类预测接口 问题总结 技术细节 1、下载模型 文件名称--a0_download_model.py 使用 ModelScope 库从模型仓…

sendfile系统调用及示例

好的&#xff0c;我们继续学习 Linux 系统编程中的重要函数。这次我们介绍 sendfile 函数&#xff0c;它是一个高效的系统调用&#xff0c;用于在两个文件描述符之间直接传输数据&#xff0c;通常用于将文件内容发送到网络套接字&#xff0c;而无需将数据从内核空间复制到用户空…

数据结构习题--删除排序数组中的重复项

数据结构习题–删除排序数组中的重复项 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 方法&…

Docker的容器设置随Docker的启动而启动

原因也比较简单&#xff0c;在docker run 的时候没有设置–restartalways参数。 容器启动时&#xff0c;需要增加参数 –restartalways no - 容器退出时&#xff0c;不重启容器&#xff1b; on-failure - 只有在非0状态退出时才从新启动容器&#xff1b; always - 无论退出状态…

JWT安全机制与最佳实践详解

JWT&#xff08;JSON Web Token&#xff09; 是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在各方之间安全地传输信息作为紧凑且自包含的 JSON 对象。它被广泛用于身份验证&#xff08;Authentication&#xff09;和授权&#xff08;Authorization&#xff…

如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题

【Python系列Bug修复PyCharm控制台pip install报错】如何解决pip安装报错ModuleNotFoundError: No module named ‘ipython’问题 摘要 在开发过程中&#xff0c;我们常常会遇到pip install报错的问题&#xff0c;其中一个常见的报错是 ModuleNotFoundError: No module named…

从三维Coulomb势到二维对数势的下降法推导

题目 问题 7. 应用 9.1.4 小节描述的下降法&#xff0c;但针对二维的拉普拉斯方程&#xff0c;并从三维的 Coulomb 势出发 KaTeX parse error: Invalid delimiter: {"type":"ordgroup","mode":"math","loc":{"lexer&qu…

直播一体机技术方案解析:基于RK3588S的硬件架构特性​

硬件配置​​主控平台​​▸ 搭载瑞芯微RK3588S旗舰处理器&#xff08;四核A762.4GHz 四核A55&#xff09;▸ 集成ARM Mali-G610 MP4 GPU 6TOPS算力NPU▸ 双通道LPDDR5内存 UFS3.1存储组合​​专用加速单元​​→ 板载视频采集模块&#xff1a;支持4K60fps HDMI环出采集→ 集…

【氮化镓】GaN取代GaAs作为空间激光无线能量传输光伏转换器材料

2025年7月1日,西班牙圣地亚哥-德孔波斯特拉大学的Javier F. Lozano等人在《Optics and Laser Technology》期刊发表了题为《Gallium nitride: a strong candidate to replace GaAs as base material for optical photovoltaic converters in space exploration》的文章,基于T…

直播美颜SDK动态贴纸模块开发指南:从人脸关键点识别到3D贴合

很多美颜技术开发者好奇&#xff0c;如何在直播美颜SDK中实现一个高质量的动态贴纸模块&#xff1f;这不是简单地“贴图贴脸”&#xff0c;而是一个融合人脸关键点识别、实时渲染、贴纸驱动逻辑、3D骨骼动画与跨平台性能优化的系统工程。今天&#xff0c;就让我们从底层技术出发…

学习游戏制作记录(剑投掷技能)7.26

1.实现瞄准状态和接剑状态准备好瞄准动画&#xff0c;投掷动画和接剑动画&#xff0c;并设置参数AimSword和CatchSword投掷动画在瞄准动画后&#xff0c;瞄准结束后才能投掷创建PlayerAimSwordState脚本和PlayerCatchSwordState脚本并在Player中初始化&#xff1a;PlayerAimSwo…

【c++】问答系统代码改进解析:新增日志系统提升可维护性——关于我用AI编写了一个聊天机器人……(14)

在软件开发中&#xff0c;代码的迭代优化往往从提升可维护性、可追踪性入手。本文将详细解析新增的日志系统改进&#xff0c;以及这些改进如何提升系统的实用性和可调试性。一、代码整体背景代码实现了一个基于 TF-IDF 算法的问答系统&#xff0c;核心功能包括&#xff1a;加载…

visual studio2022编译unreal engine5.4.4源码

UE5系列文章目录 文章目录 UE5系列文章目录 前言 一、ue5官网 二.编译源码中遇到的问题 前言 一、ue5官网 UE5官网 UE5源码下载地址 这样虽然下载比较快,但是不能进行代码git管理,以后如何虚幻官方有大的版本变动需要重新下载源码,所以我们还是最好需要visual studio2022…

vulhub Earth靶场攻略

靶场下载 下载链接&#xff1a;https://download.vulnhub.com/theplanets/Earth.ova 靶场使用 将压缩包解压到一个文件夹中&#xff0c;右键&#xff0c;用虚拟机打开&#xff0c;就创建成功了&#xff0c;然后启动虚拟机&#xff1a; 这时候靶场已经启动了&#xff0c;咱们现…

Python训练Day24

浙大疏锦行 元组可迭代对象os模块

Spring核心:Bean生命周期、外部化配置与组件扫描深度解析

Bean生命周期 说明 程序中的每个对象都有生命周期&#xff0c;对象的创建、初始化、应用、销毁的整个过程称之为对象的生命周期&#xff1b; 在对象创建以后需要初始化&#xff0c;应用完成以后需要销毁时执行的一些方法&#xff0c;可以称之为是生命周期方法&#xff1b; 在sp…

日语学习-日语知识点小记-进阶-JLPT-真题训练-N1阶段(1):2017年12月-JLPT-N1

日语学习-日语知识点小记-进阶-JLPT-真题训练-N1阶段&#xff08;1&#xff09;&#xff1a;2017年12月-JLPT-N1 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰&#xff08;3&#xff09;真题训练2、真题-2017年12月-JLPT-N1&#xff08;1&a…

(一)使用 LangChain 从零开始构建 RAG 系统|RAG From Scratch

RAG 的主要动机 大模型训练的时候虽然使用了庞大的世界数据&#xff0c;但是并没有涵盖用户关心的所有数据&#xff0c; 其预训练令牌&#xff08;token&#xff09;数量虽大但相对这些数据仍有限。另外大模型输入的上下文窗口越来越大&#xff0c;从几千个token到几万个token,…

OpenCV学习探秘之一 :了解opencv技术及架构解析、数据结构与内存管理​等基础

​一、OpenCV概述与技术演进​ 1.1技术历史​ OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是由Intel于1999年发起创建的开源计算机视觉库&#xff0c;后来交由OpenCV开源社区维护&#xff0c;旨在为计算机视觉应用提供通用基础设施。经历20余年发展&…

什么是JUC

摘要 Java并发工具包JUC是JDK5.0引入的重要并发编程工具&#xff0c;提供了更高级、灵活的并发控制机制。JUC包含锁与同步器&#xff08;如ReentrantLock、Semaphore等&#xff09;、线程安全队列&#xff08;BlockingQueue&#xff09;、原子变量&#xff08;AtomicInteger等…