Skip to content
返回

Go语言基础

1

目录

点击展开

Go语言基础

认识

Go(又称Golang) 由Google开发,于2009年首次公开发布。它旨在提供简洁、高效、可靠的软件开发解决方案。

Golang是一种静态强类型、编译型语言

支持最强大的并发、内存管理、垃圾回收机制等

下载安装

官网: https://go.dev/(英) 可访问 中国镜像站 https://golang.google.cn/

安装教程参考:https://learn.microsoft.com/zh-cn/azure/developer/go/configure-visual-studio-code

以上步骤操作完重新打开VSCode就可以使用了

Go语言声明

const e = 2.7182 // 批量声明 const ( pi = 3.1415 e = 2.7182 ) // 使用iota 关键字进行递增计数 // iota 在const关键字出现时将被重置为 0 const ( n1 = iota //0 n2 //1 n3 //2 n4 //3 ) ```

关键字

关键字是 Go 语言中预先保留的单词,在程序中有特殊含义,不能用来定义变量或常量名字。

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

数据类型

Go 语言中数据类型分为:基本数据类型复合数据类型

基本数据类型

整型

整型的类型有很多中。我们可以根据具体的情况来进行定义 有符号整型int8,int16,int32,int64 无符号整型 : uint8, uint16, uint32, uint64

提示!

  • 有符号(Signed) → 能赋值正能负数,但正数范围小。
  • 无符号(Unsigned) → 只能赋值正数,但能存更大的正数。

如果我们直接写int也是可以的,它在不同的电脑操作系统中,int的大小是不一样的

32位操作系统:int -> int32 64位操作系统:int -> int64

![[../../../assets/images/2025/Pasted image 20250819113643.png]]

var num8 uint8 = 128
var num16 uint16 = 32768
var num32 uint32 = math.MaxUint32
var num64 uint64 = math.MaxUint64

浮点型

浮点型表示存储的数据是实数,如3.145

32位操作系统:float32 64位操作系统:float64

var num1 float32 = math.MaxFloat32
var num2 float64 = math.MaxFloat64

提示: 我们知道浮点数能表示的数值很大,但是浮点数的精度却没有那么大:

  • float32 的精度只能提供大约 6 个十进制数(表示小数点后 6 位)的精度。
  • float64 的精度能提供大约 15 个十进制数(表示小数点后 15 位)的精度。

布尔值

Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true(真)和false(假)两个值。

var d bool = true
f := false

注意        布尔类型变量的默认值为false。
       Go 语言中不允许将整型强制转换为布尔型.
       布尔型无法参与数值运算,也无法与其他类型进行转换。

字符串

字符串的值为双引号(“)中的内容

s1 := "hello"
s2 := "你好"

复合数据类型

数组

是同一种数据类型的固定长度的序列。

  • 数组定义:var a [len]int,比如:var a [5]int,一旦定义,长度不能变。
  • 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1\
  • 数组是值类型赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。
// 数组初始化
var arr1 = [3]int{1, 2, 3}
fmt.Println(arr1) // [1, 2, 3]

// 短声明
arr2 := [3]int{4, 5, 6}
fmt.Println(arr2) // [4, 5, 6]

// 部分初始化,为初始化为0值
arr3 := [5]int{1, 2}
fmt.Println(arr3) // [1, 2, 0, 0, 0]

// 通过指定索引,方便对数组某几个元素赋值
arr4 := [5]int{0: 1, 3: 4}
fmt.Println(arr4) // [1, 0, 0, 4, 0]

// 根据初始化的值,指定长度
arr5 := [...]int{1, 2, 3}
fmt.Println(arr5) // [1, 2, 3]

// 多维数组
var arr6 = [2][3]int{{1, 2, 3}, {4, 5, 6}}
fmt.Println(arr6) // [[1 2 3] [4 5 6]]

切片

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。

切片是一个引用类型,它的内部结构包含指针、长度和容量。切片一般用于快速地操作一块数据集合。

格式var name []T

  • name:表示变量名
  • T:表示切片中的元素类型

切片的定义方式与数组的定义方式的区别在于,数组在初始化的时候我们将一个具体大小给他设定了,而切片没有定义大小。

使用内置len()函数求长度 使用内置cap()函数求容量

func main() {
	var a []string              //声明一个字符串切片
	var b = []int{}             //声明一个整型切片并初始化
	var c = []bool{false, true} //声明一个布尔切片并初始化
	// 使用内置 make([]T, len, cap) 定义切片
	numList := make([]int, 3, 5)
	fmt.Println(numList) // [0 0 0]
	fmt.Println(len(numList)) // 3
	fmt.Println(cap(numList)) // 5
	// 通过数组进行切片截取
	a := [5]int{1, 2, 3, 4, 5}
	// 切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片(通过索引截取)
	// 格式:数组变量[起始位置:结束位置]
	// 切片中不包含结束位置的元素
	s := a[1:3]
	fmt.Println(s) // [2 3]
	
	/*
		a[2:]  // 等同于 a[2:len(a)]
		a[:3]  // 等同于 a[0:3]
		a[:]   // 等同于 a[0:len(a)]
	*/
	
	// 创建多维切片
	nameList := [][]string{
		{"1", "张三"},
		{"2", "李四"},
		{"3", "王二"},
		{"4", "麻子"},
	}	
	fmt.Println(nameList) // [[1 张三] [2 李四] [3 王二] [4 麻子]]
}
用append内置函数操作切片(切片追加)
package main
import (
    "fmt"
)
func main() {
    var a = []int{1, 2, 3}
    fmt.Printf("slice a : %v\n", a) // [1 2 3]
    var b = []int{4, 5, 6}
    fmt.Printf("slice b : %v\n", b) // [4 5 6]
    c := append(a, b...)
    fmt.Printf("slice c : %v\n", c) // [1 2 3 4 5 6]
    d := append(c, 7)
    fmt.Printf("slice d : %v\n", d) // [1 2 3 4 5 6 7]
    e := append(d, 8, 9, 10)
    fmt.Printf("slice e : %v\n", e) // [1 2 3 4 5 6 7 8 9 10]
}

超出原 slice.cap 限制,就会重新分配底层数组,即便原数组并未填满, 通常以 2 倍容量重新分配底层数组

指针

指针也是一种类型,也可以创建变量,称之为指针变量。指针变量的类型为 *Type,该指针指向一个 Type 类型的变量。指针变量最大的特点就是存储的某个实际变量的内存地址,通过记录某个变量的地址,从而间接的操作该变量。 ![[../../../assets/images/2025/Pasted image 20250826104221.png]]

指针声明获取格式

  • var 变量名 *类型 = new(类型)
  • 填入值:*变量名 = 值
  • 获取指针:&变量名
  • 获取值:*变量名
package main
import (
    "fmt"
)
func main() {
	var num int = 10
	p := &num // 将地址值指针赋值给p变量
	fmt.Println(p) // 输出地址值指针 0x14000010230
	fmt.Println(*p) // 通过指针访问值  // 10
	fmt.Println(&num) // 0x14000010230
	fmt.Println(num) // 10
	

	// 修改指针指向的值
	*p = 20
	fmt.Println(num) // 20

	// new 先创建指针分配好内存,再给指针写入值
	var p1 *int = new(int)
	*p1 = 30
	fmt.Println(*p1) // 30
}

只需要记住两个符号:&(取地址)和*(根据地址取值)。 总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:

  1. 对变量进行取地址(&)操作,可以获得这个变量的指针变量。 >2. 指针变量的值是指针地址。 >3. 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil

package main

import "fmt"

func main() {
    var p *string
    fmt.Println(p)
    fmt.Printf("p的值是%s/n", p)
    if p != nil {
        fmt.Println("非空")
    } else {
        fmt.Println("空值")
    }
}

Map

map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型。它类似于其他编程语言中的哈希表或字典,提供了快速的插入、删除和查找操作

map中的数据是无序排列 map中的key只能是string|int类型

package main
import (
    "fmt"
)
func main() {
	// 定义方式
	// make方式  格式:name := make(map[KeyType]ValueType) 或者 make(map[KeyType]ValueType, [cap])
	// KeyType:表示键的类型。 ValueType:表示键对应的值的类型。 cap表示容量
	make1 := make(map[string]string) 
	fmt.Printf(make1) // map[]
	
	// 通过字面量
	var userInfo1 map[string]string = map[string]string{
        "username": "zhangsan",
        "password": "123456",
    }
	// 通过短声明
	userInfo2 := map[string]string{
        "username": "zhangsan",
        "password": "123456",
    }
    fmt.Printf(userInfo2) // map[username:zhangsan password:123456]
    
    userList := map[int]string{
	    1: '张三',
	    2: '李四',
	    3: '王二',
    }
    // 添加元素到map
	userList[4] = "麻子"
	fmt.Println(userList) // map[1:张三 2:李四 3:王二 4:麻子]
	// 更新map
	userList[4] = "mazi"
	fmt.Println(userList) // map[1:张三 2:李四 3:王二 4:mazi]
	// 获取元素
	fmt.Println(userList[4]) // mazi
	// 删除元素
	delete(userList, 4)
	fmt.Println(userList) // map[1:张三 2:李四 3:王二]
	
	//判断键值是否存在  value,ok := map[key]
	u3, ok := userList[3]
	fmt.Println(ok) // true
	fmt.Println(u3) // 张三

	u4, ok := userList[4]
	fmt.Println(ok) // false
	fmt.Println(u4) // 
	
	// 循环map
	for key, value := range m1 {
		/*
		%s、%d都是占位符,%s是用于插入字符串类型,%d用于插入整数类型的值
		*/
		fmt.Printf("key: %s, value: %d\n", key, value)
	}
	
}

结构体

理解

  • Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。
  • Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。

简单理解就是go语言中的类成为结构体,用typestruct关键字进行实现

type 类型名 struct {
	字段名 字段类型
	字段名 字段类型

}
/*
1.类型名:标识自定义结构体的名称,在同一个包内不能重复。
2.字段名:表示结构体字段名。结构体中的字段名必须唯一。
3.字段类型:表示结构体字段的具体类型。
*/

内置函数

new

new是一个内置的函数,用于分配内存

*函数签名:func new(Type) Type

  1. Type表示类型,new函数只接受一个参数,这个参数是一个类型
  2. *Type表示类型指针,new函数返回一个指向该类型内存地址的指针。
func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a) // 10
}

make

make也是用于内存分配的,区别于new,它只用于**切片(slice)、map以及通道(channel)**的内存创建,它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了

函数签名:func make(t Type, size …IntegerType) Type

func main() {
    var b map[string]int
    b = make(map[string]int, 10)
    b["测试"] = 100
    fmt.Println(b) // map[测试:100]
}

new与make的区别

  1. 二者都是用来做内存分配的。
  2. make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
  3. 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。

常用库解析

fmt

用于格式化输出文本

  1. %v:通用类型占位符。可以表示任意值的类型。
  2. %d:10进制整数
  3. %f:浮点数
  4. %s:字符串
  5. %t:布尔值
  6. %c:字符(Unicode码点)
  7. %p:指针地址
  8. %e/%E:科学计数法
  9. %b:二进制整数
  10. %o:八进制整数
  11. %x/%X:十六进制整数
  12. %U:Unicode格式,表示为U+十六进制数
  13. %T:打印值的类型

模块

模块是Go管理依赖项的方式。 模块是一组被发布、有版本号并一起分发的软件包。块可以直接从版本控制存储库或模块代理服务器下载。 有关模块的系列教程,请参阅https://golang.google.cn/doc/tutorial/create-module 默认情况下,go命令可能会从 https://proxy.golang.org 下载模块。它可能会使用位于 https://sum.golang.org 的校验码数据库来验证模块。这两个服务均由谷歌的 Go 团队运营。这些服务的隐私政策分别可在 https://proxy.golang.org/privacyhttps://sum.golang.org/privacy 找到。


Share this post on:

上一篇文章
炫酷的CSS loading加载动画(拒绝废话版)
下一篇文章
React知识点总结