文章目录
golang
golang语法
数据类型
| 类型 | 名称 | 长度 | 零值 | 说明 |
|---|---|---|---|---|
| bool | 布尔类型 | 1 | false | 其值不为真即为假,不可以用数字代表true或false |
| byte | 字节型 | 1 | 0 | uint8别名 |
| rune | 字符类型 | 4 | 0 | 专用于存储unicode编码,等价于uint32 |
| int, uint | 整型 | 4或8 | 0 | 有符号32位或无符号64位 |
| int8 | 整型 | 1 | 0 | -128 ~ 127, |
| uint8 | 整型 | 1 | 0 | 0 ~ 255 |
| int16 | 整型 | 2 | 0 | -32768 ~ 32767, |
| uint16 | 整型 | 2 | 0 | 0 ~ 65535 |
| int32 | 整型 | 4 | 0 | -2147483648 到 2147483647 |
| uint32 | 整型 | 4 | 0 | 0 到 4294967295(42亿) |
| int64 | 整型 | 8 | 0 | 0 到 18446744073709551615(1844京) |
| uint64 | 整型 | 8 | 0 | -9223372036854775808到 9223372036854775807 |
| float32 | 浮点型 | 4 | 0.0 | 小数位精确到7位 |
| float64 | 浮点型 | 8 | 0.0 | 小数位精确到15位 |
| complex64 | 复数类型 | 8 | ||
| complex128 | 复数类型 | 16 | 64 位实数和虚数 | |
| uintptr | 整型 | 4或8 | ⾜以存储指针的uint32或uint64整数 | |
| string | 字符串 | "" | utf-8字符串 |
包
+ go语言中不在提倡库的概念,都叫包
+ 同一个文件夹下面的包名必须一致
- 在文件夹创建文件,默认包名和文件夹一致(也可以修改)
变量
Go语言引入了关键字var,而类型信息放在变量名之后
变量声明
-
变量定义(要求定义的变量必须使用,如果不使用就会报错)
-
最基础的 var 变量名 变量类型
-
直接赋值的 var 变量名 = "string"
-
第三种 ,直接推导类型 变量名 := 10
:=只能在变量初次定义的时候使用,因为在这个时候系统会给变量申请空间
-
-
多个变量一起定义
go
var a,b,c,d,e int
变量赋值
go
var a int = 10
var b int = 20
var c,d int
c = 30
d = 40
fmt.Println(a,b,c,d)
- 多个变量一起赋值
go
a,b,c,d,_ := 1,2,3,4
a,d = d,a // 值交换
- 要求变量的个数和值的个数必须保持一致
自动推导类型
go
a := 30
fmt.Println(a)
匿名变量 其实就是-
示例:
go
/*
*/
//默认的包名
package main
//导入包
import "fmt"
func main()
{
//go 语言中定义变量, 在go语言中定义了变量就必须使用
//1 先定义变量,在赋值
var a int;
a = 10;
//2 直接赋值
var b = "string";
//3 自动推导类型 := 只能在变量定义的时候使用
c:= true;
/*
var d := 3.14;
这种定义是错误的,因为在var 会申请空间, := 也会申请空间
*/
fmt.Println("hello world!" , a, b, c);
}
//直接执行
$ go run test.go
hello world!
//直接执行
$ go run test.go
hello world! 10
//先编译
$ go build test.go
//在执行
$./test
hello world! 10 string
$ go run test.go
hello world! 10 string true
函数
- 普通函数
- 不定参函数
函数的基本格式
在 Go 语言中,函数使用 func 关键字定义,基本语法如下:
go
func 函数名(参数列表) (返回值列表) {
// 函数体
}
1. 普通函数定义
- 函数名:遵循标识符命名规则,首字母大写表示包外可导出(public),小写表示包内私有(private)。
- 参数列表:多个参数用逗号分隔,类型写在参数名后面。如果相邻参数类型相同,可以省略前面参数的类型声明。
- 返回值列表 :可以返回零个、一个或多个值。多个返回值需要用括号
()括起来。
示例:
go
// 无参数无返回值
func SayHello() {
fmt.Println("Hello, World!")
}
// 带参数无返回值
func PrintSum(a int, b int) {
fmt.Println(a + b)
}
// 参数类型相同可简写
func PrintSum2(a, b int) {
fmt.Println(a + b)
}
// 单个返回值
func Add(a, b int) int {
return a + b
}
// 多个返回值(匿名返回)
func Divide(a, b int) (int, int) {
quotient := a / b
remainder := a % b
return quotient, remainder
}
// 多个返回值(有名返回)
func DivideNamed(a, b int) (q int, r int) {
q = a / b
r = a % b
return // 直接 return,q 和 r 已被赋值
}
2. 不定长参数(Variadic Functions)
Go 支持不定长参数,使用 ... 语法,表示该参数可以接收任意数量的同类型值。不定长参数必须是参数列表中的最后一个参数。
示例:
go
// 不定长参数示例
func Sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func PrintInfo(name string, scores ...int) {
fmt.Printf("Name: %s\n", name)
fmt.Printf("Scores: %v\n", scores)
}
func main() {
fmt.Println(Sum(1, 2, 3, 4, 5)) // 输出: 15
fmt.Println(Sum()) // 输出: 0,不定参可以是0个
PrintInfo("Alice", 90, 85, 95)
}
在函数内部,不定长参数被当作切片(slice)处理,可以通过 range 遍历。
3. 返回值详解
Go 函数的返回值有两种形式:匿名返回 和有名返回。
- 匿名返回 :在函数签名中只声明返回类型,不指定变量名。函数体内使用
return语句显式返回具体值。 - 有名返回 :在函数签名中为返回值指定变量名。这些变量在函数开始时被初始化为其零值,在函数体内可以直接使用。
return语句可以不带参数,此时返回当前有名变量的值。
注意:
- 如果函数有多个返回值,要么全部使用匿名返回,要么全部使用有名返回,不能混用。
- 有名返回时,
return后面可以跟值,此时返回值变量的值会被覆盖。 - 有名返回时,
return后面可以不跟任何值,此时返回当前已赋值的返回值变量。
示例对比:
go
// 匿名返回
func GetCoordinates() (float64, float64) {
x := 10.5
y := 20.3
return x, y
}
// 有名返回
func GetCoordinatesNamed() (x float64, y float64) {
x = 10.5
y = 20.3
return // 等价于 return x, y
}
// 有名返回,return 带值会覆盖
func GetCoordinatesOverride() (x float64, y float64) {
x = 10.5
y = 20.3
return 30.0, 40.0 // x 和 y 的值被覆盖,最终返回 (30.0, 40.0)
}
4. defer 延迟调用
defer 语句用于延迟函数的执行,直到包含它的函数返回。defer 通常用于资源清理(如关闭文件、解锁互斥锁)或确保某些操作在函数结束时执行。
特性:
defer后面的语句会在函数返回之前执行。- 一个函数中可以有多个
defer语句,它们以 栈(LIFO,后进先出) 的顺序执行。 defer可以跟函数调用或匿名函数。defer语句中的参数会在defer语句执行时立即求值,但函数调用会延迟。
示例:
go
func TestDefer() {
defer fmt.Println("defer 1: 最后执行")
defer fmt.Println("defer 2: 倒数第二执行")
fmt.Println("正常执行: 最先执行")
}
// 输出:
// 正常执行: 最先执行
// defer 2: 倒数第二执行
// defer 1: 最后执行
// defer 用于资源清理
func ReadFile(filename string) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close() // 确保函数返回前关闭文件
content, err := io.ReadAll(file)
if err != nil {
return "", err
}
return string(content), nil
}
// defer 参数立即求值示例
func DeferEvaluation() {
i := 0
defer fmt.Println("defer i =", i) // i 的值此时是 0
i++
fmt.Println("normal i =", i) // i 的值现在是 1
}
// 输出:
// normal i = 1
// defer i = 0
5. 函数调用与可见性
- 包内调用:同一个包内的函数,无论首字母大小写,都可以直接调用。
- 跨包调用:只有首字母大写的函数(公开函数)才能被其他包调用。
- main 包特殊 :在
main包中,如果多个文件属于同一个包,它们之间的函数调用需要编译时指定所有相关文件。
总结: Go 的函数设计简洁而强大,支持多返回值、不定长参数、延迟执行等特性,结合严格的可见性规则,使得代码模块化清晰,易于维护。### 函数的返回值
- 注意,如果返回值有多个,是匿名返回的话就都必须是匿名返回,如果是有名返回的话就都必须是名返回
- 如果返回值中return后面跟有确定的值,那么当有名返回的时候,值会被覆盖
- 如果有名返回的话,return后可以不跟任何值(会被覆盖)
- defer延迟调用 在函数结束的时候调用defer后面的语句,语句只能有一条
- defer的执行顺序在一个函数内是栈结构,是先进后出 ,在return函数后面语句执行完之后然后执行defer的语句
- defer后面可以跟函数调用,也可以跟匿名函数
go
//有名返回值
func Test(a, b int)(r sring){
defer fmt.Println("33333") //先进后出
defer fmt.Println("22222")
defer fmt.Println("11111")
fmt.Println("hello")
r = a+b
return r
}
//匿名返回
func MyFunc(a int)(int,int){
}
功能管理
可以通过go env命令来查看go有关的环境
goroot
存放go语言的源码,还会存放Go语言的标准库 /usr/local/go
gopath
非常重要的命令是go get github.com/
放置go get下载的内容,同时也放扩展
go run /go build的时候go语言会在这两个目录下面找你导入的包,如果找不到,就会提示错误
所以我们一般创建的项目都放在gopath中
跨包的使用
- 当存在跨包之间调用的时候,函数或者变量首字母都需要大写
- 当在main包中,存在互相调用的情况,在编译或者是执行的时候,都需要手动指定调用的函数所在的文件
- _的作用,第一个是调用包担不使用包,第二个作用是会调用包中的init函数