Go语言学习笔记

article/2025/4/20 11:57:34

Go学习笔记

Go学习笔记

  • Go学习笔记
    • Go语言基础语法
      • 行分隔行
    • 一、变量
      • 1.1 变量的声明
      • 1.2 初始化变量
      • 1.4 多个变量同时赋值
      • 1.5 匿名变量(_)
    • 二、常量
    • 三、基本数据类型
      • 3.1 整型
      • 3.2 浮点型
      • 3.3 布尔型
      • 3.4 字符串
        • 3.4.1 字符串常见转义符
        • 3.4.2 反引号定义多行字符串
      • 3.5 字符
    • 四、数据类型的转换
    • 五 、指针
      • 5.1 认识指针地址和指针类型
      • 5.2 从指针获取指针指向的值
      • 5.3 使用指针修改值
      • 5.4 创建指针的另一种方法--new()函数
      • 六、字符串应用
      • 6.1 计算机字符串长度 -- len()
      • 6.2 遍历字符串 -- 获取每个字符串
      • 6.3 获取字符串的某一段字符
      • 6.4 修改字符串
      • 6.5 连接字符串
      • 6.6 格式化
    • 七、枚举
      • 7.1 枚举 -- 一组常量值
      • 7.2 枚举--将枚举值转换为字符串
    • 八、 类型别名
      • 8.1 区分类型别名与类型定义
      • 8.2 非本地类型不能定义方法
      • 8.3 在结构体成员嵌入时使用别名
    • 九、条件语句
      • 8.1 if语句
        • 语法
      • 8.2 if...else语句
        • 语法
      • 8.3 switch case语句:
    • 十、for循环
      • 语法
        • 实例
        • 实例
        • 实例
        • 实例
        • 实例
    • 十一、数组
      • 11.1 声明数组
      • 11.2 初始化数组
      • 11.3 访问数组元素
      • 11.4多维数组
      • 11.5初始化多维数组
      • 11.6 访问多维数组
      • 十二、函数
      • 12.1 函数定义
      • 12.2 函数返回多个值
      • 12.3 函数return值的几种情况
        • 分三种情况
      • 12.4 可变参数
      • 12.5 匿名函数
      • 十三、defer的用途
      • 十四、输入的使用
      • 十四、输入的使用

Go语言基础语法

行分隔行

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,

但是可以使用分号;结尾,如果当你将多个语句写在同一行时,则必须使用分号;

一、变量

1.1 变量的声明

功能:存储用户的数据

注意: 变量必须经过声明才能开始使用

标准格式:

var 变量名 变量类型

变量的声明以关键字 var 开头,行尾不需要写分号

package main
import ( "fmt" )
func main() {var a intvar b stringvar c []float32var d  func () boolvar e  struct {x int}
} 

代码说明:

  • 第3行,声明一个整型类型的变量,可以保存整数数值。

  • 第4行,声明一个字符串类型的变量。

  • 第5行,声明一个 32 位浮点切片类型的变量,浮点切片表示由多个浮点类型组成的数据结构。

  • 第6行,声明一个返回值为布尔类型的函数变量,这种形式一般用于回调函数,即将函数以变量的形式保存下来,在需要的时候重新调用这个函数。

  • 第7行,声明一个结构体类型的变量,这个结构体拥有一个整型的 x 字段。

使用var关键字和括号批量声明(推荐

var (a intb stringc []float32d  func () boole  struct {x int}
)

使用关键字var和括号,可以将一组变量定义放在一起。

1.2 初始化变量

变量的声明可以包含初始值,每一个变量对应一个值。

如果初始化值已存在,则可以省略类型;变量会从初始值中获得类型。

变量初始化的标准格式:

var 变量名 类型 = 表达式

简化形式:

var 变量名 = 表达式

例如:

var x int = 100

可以写成:

var x = 100

默认值:

没有明确初始值的变量声明会被赋予它们一个默认值:

整型和浮点型变量的默认值为 0。
字符串变量的默认值为空字符串。
布尔型变量默认为 bool。
切片、函数、指针变量的默认为 nil。

注意:变量已经被声明过了,再次声明并赋值,使用短变量声明会编译报错

var p string
p :=  '123'
fmt.Println(p)
// 错误信息:no new variables on left side of :=(44.4)
// var p 声明了p变量, p := '123' 会再次声明并赋值

注意:由于使用了 :=,而不是赋值的 =,因此推导声明写法的左值变量必须是没有定义过的变量。若定义过,将会发生编译错误。

注意:在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名可能是重复声明的,编译器也不会报错,例如:

x, z := a, b
y, z := a, b

1.4 多个变量同时赋值

使用Go的“多重赋值特性”,可以轻松完成变量交换的任务。

package` `main
import` `"fmt"
func main() {var a = 100var b = 200a, b = b, agofmt.Println(a, b)
}

多重赋值时,变量的左值和右值按从左到右的顺序赋值。

1.5 匿名变量(_)

在使用多重赋值时,如果不需要在左值中接收变量,可以使用匿名变量。

匿名变量用一个下划线 _ 来表示,使用匿名变量时,只需要在变量声明的地方使用下划线替换即可。例如:

var a int
a, _ = 100, 200

注意:匿名变量不占用命名空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用。

package main
import ("fmt")
func main() {a1, _ := getData()_, b1 := getData()fmt.Println(a1, b1)
}type IntSlice []int
// 编写一个len方法,提供切片的长度
func (p IntSlice) Len() int { return len(p)}
// 根据提供i,j元素索引,两个元素进行比较,返回比较结果
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j]}
// 根据提供i,j元素索引,交换两个元素的值
func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i]}func getData() (int, int) {return 200, 100
}

二、常量

常量是恒定不变的值,例如圆周率。

常量的声明与变量类似,只不过是使用 const 关键字。

常量可以是字符、字符串、布尔值和数值。

常量不能用 := 语法声明。

常量的声明, 例如:

const pi = 3.1415926

注意:常量在声明的时候必须赋值。

多个变量可以一起声明,类似的,多个变量也可以一起声明。例如:

const(pi = 3.1415926e = 2.718281
)

三、基本数据类型

Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有切片、结构体、函数、map、通道(channel)等。

Go 语言的基本类型和其他语言大同小异。

3.1 整型

整型可以分成以下两个大类:

按长度分为:int8、int16、int32、int64

对应的无符号整型:uint8、uint16、uint32、uint64

其中,uint8 就是我们熟知的 byte 型.

3.2 浮点型

Go语言支持两种浮点型数:

float32、float64.

注意:没有float

Go语言的浮点型默认声明为float64.

3.3 布尔型

布尔型数据只有 true(真)和 false(假)两个值。

注意:

在Go语言中,
truefalse均为小写
不允许将整型强制转换为布尔型

3.4 字符串

字符串的两种表示形式:

\1. 双引号,会识别转义字符

\2. 反引号,不会识别转义字符。以字符串的原生形式输出,包括换行和特殊字符。

3.4.1 字符串常见转义符

转义符含义
\r回车符(返回行首)
\n换行符
\t制表符
单引号
"双引号
\反斜杠

3.4.2 反引号定义多行字符串

const str = ` 第一行
第二行
第三行
\r\n`
fmt.Println(str)

代码运行结果:

第一行
第二行
第三行
\r\n

3.5 字符

字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。

Go语言的字符有以下两种:

  • 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII码的一个字符。
  • 另一种是 rune 类型,代表一个 UTF-8 字符。当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型实际是一个 int32。

四、数据类型的转换

Go语言使用类型前置加括号的方式进行类型转换,一般格式如下:

T(表达式)

其中,T 代表要转换的类型。表达式包括变量、复杂算子和函数返回值等。

注意:在类型转换时,需要考虑两种类型的关系和范围,是否会发生数值截断等。

package mainimport "fmt"func main(){var n1 int = 20var n2 float64 = float64(n1)n2 = n2 + 3.6var n3 int32 = int32(n2) // 当将一个float类型转成 int时,是直接去掉小数点后的部分fmt.Printf("n1 type=%T, val=%v; n2 type=%T, val=%v; n3 type=%T, val=%v\n",n1, n1, n2, n2, n3, n3)
}

代码运行结果:

n1 type=int, val=20; n2 type=float64, val=23.6; n3 type=int32, val=23

五 、指针

两个核心:

一种是类型指针,允许对这个指针类型的数据进行修改。 传递数据使用使用指针,而无须拷贝数据 类型指针不能进行偏移和运算

二种是切片, 由指向起始元素的原始指针、元素数量和容量组成

5.1 认识指针地址和指针类型

每个变量在运行时都会被内存分配一个地址,这个地址代表变量在内存中的位置 使用“&”操作符放在变量前面对变量进行“取地址”操作 格式:

     ptr := &variable   //variable的类型为T

其中v代表被取地址的变量,被取地址的variable使用ptr变量进行接收,ptr的类型为“T”,称作T的指针类型。“”代表指针

package mainimport ("fmt""math"
)func main() {  var cat int = 1var str2 string = "banana"fmt.Printf("%p, %p\n", &cat, &str2)
}//0xc00004e0e8, 0xc0000421f0 为cat,str2取地址后的指针值

注意:变量、指针和地址三种的关系是:每个变量都拥有地址,指针的值就是地址

5.2 从指针获取指针指向的值

对变量“&”取地址操作后获得这个变量的指针,对指针使用“*”操作,就是指针取值

package mainimport ("fmt""math"
)
func main() {var house = "Malibu Point 10880, 90265"// 对字符串取地址,ptr1类型为*stringptr1 := &house// 打印ptr类型fmt.Printf("ptr1 类型:%T\n", ptr1)// 打印ptr指针地址fmt.Printf("ptr1 地址:%p\n", ptr1)// 对指针进行取值操作value := *ptr1// 取值后类型fmt.Printf("value 类型:%T\n", value)// value值fmt.Printf("value:%s\n", value)
}
// ptr1 类型:*string
// ptr1 地址:0xc000042200
// value 类型:string
// value:Malibu Point 10880, 90265

总结:

取地址“&”和取值“”是一对互补操作符,“&”取地址,"&"根据地址取出地址指向的值

1.对变量进行其地址(&)操作,可获得这个变量的指针变量

2.指针变量的值是指针地址

3.对指针变量进行取值()操作,可以获得指针变量指向的原变量的值

5.3 使用指针修改值

x, y := 1,2

package mainimport ("fmt""math"
)func main() {//错误示例swap1(&x, &y)fmt.Println("x: ",x, "y:", y)//x:  1 y:  2//正确swap(&x, &y)fmt.Println("x: ", x, "y: ",y)//x:  2 y:  1
}
// 交换函数
func swap(a, b *int) {// 取a的指针的值,赋给临时变量tt := *a//取b指针的值,赋值给a指针指向的变量*a = *b//a指针的值赋值给b指针指向的变量*b = t
}// 错误示例
func swap1(a, b *int) {b, a = a, b
}

5.4 创建指针的另一种方法–new()函数

new(类型)

str3 := new(string)
*str3 = "ninja"
fmt.Println(*str3)
fmt.Println(str3)
//ninja
//0xc000042230

六、字符串应用

6.1 计算机字符串长度 – len()

go 语言字符串都是以UTF-8格式保存,每个中文占用3个字符

tip1 := "genji is a ninja"
fmt.Println(len(tip1))
// 16
tip2 := "忍者无敌"
fmt.Println(len(tip2))
//12
// 使用RuneCountInString()统计Uncode字符数量
fmt.Println(utf8.RuneCountInString("忍者"))

总结

  • ASCII字符串长度使用len()函数
  • Unicode字符串长度使用utf8.RuneCountInString()函数

6.2 遍历字符串 – 获取每个字符串

两种写法

  1. 遍历每一ASCII字符, 使用for循环遍历
theme := "阻击 start"for i := 0; i < len(theme); i++ {fmt.Printf("ascii: %c %d\n", theme[i], theme[i])}// ascii: é 233// ascii: • 152// ascii: » 187// ascii: å 229// ascii: • 135// ascii: » 187// ascii:   32// ascii: s 115// ascii: t 116// ascii: a 97// ascii: r 114

  1. 按Unicode字符遍历字符串
  for _, s := range theme {fmt.Printf("Unicode %c %d\n", s, s)}// Unicode 阻 38459// Unicode 击 20987// Unicode   32// Unicode s 115// Unicode t 116// Unicode a 97// Unicode r 114// Unicode t 116

总结:

  • ASCII字符串遍历直接使用下标
  • Unicode字符串遍历使用for range

6.3 获取字符串的某一段字符

string.Index() 在字符串中搜索另一个子串

tracer := "努力拥抱每一天,不断成长"
comma := strings.Index(tracer, "每一天")
posi := strings.Index(tracer[comma:], "成长")fmt.Println(comma, posi, tracer[comma+posi:])// 12 18 成长

总结:

  • strings.Index:正向搜索子字符串
  • string.LastIndex: 反向搜索自字符串

搜索的起始位置可以通过切片偏移制作

6.4 修改字符串

go语言无法直接修改每一个字符元素,只能通过重新构造新的字符串并赋值给原来的字符串变量

angel := "Hero nerver die"arrayBytes := []byte(angel)for i := 5; i <= 10; i++ {arrayBytes[i] = '-'}fmt.Println(arrayBytes)// [72 101 114 111 32 45 45 45 45 45 45 32 100 105 101]fmt.Println(string(arrayBytes))// Hero ------ die

总结

  • Go语言的字符串是不可以改变的
  • 修改字符串时,可以将字符串转换为[]byte进行修改
  • []byte 和string 可以通过强制类型转换互换

6.5 连接字符串

可以使用加号“+”连接 可以使用类似于StringBuilder的机制连接,更高效

hamer := "GO GO GO"
sickle := "You Can"// 声明字节缓冲var stringBuilder bytes.Buffer// 将字符串写入缓冲区stringBuilder.WriteString(hamer)stringBuilder.WriteString(sickle)//将缓冲以字符串形式输出fmt.Println(stringBuilder.String())// GO GO GOYou Can

  • bytes.Buffer可以缓冲并写入各种字节数组,字符串也是一种字符串数组,使用writeString()
  • 将需要连接的字符串,通过bytes.Buffer声明缓冲stringBuilder调用WriteString()方法写入里面,
  • 再通过stringBuilder.String()方法将缓冲转换为字符串

6.6 格式化

写法: fmt.Sprintf(格式化样式,参数列表)

格式化样式:字符串形式,格式化动词以%开头

参数列表:多个参数以逗号分隔,个数必须与格式化中样式个数一一对应

var progress = 2var target = 8// 两参数格式化title := fmt.Sprintf("以完成%d个任务,还差%d个就完成", progress, target)fmt.Println(title)// 以完成2个任务,还差8个就完成pi := math.Pi// 按数值本身格式输出variant := fmt.Sprintf("%v %v %v", "月球基地", pi, true)   fmt.Println(variant)// 月球基地 3.141592653589793 trueprofile := &struct {Name stringHP   int}{Name: "stat",HP: 150,}fmt.Printf("使用'%%+v' %+v\n", profile)fmt.Printf("使用'%%#v' %#v\n", profile)fmt.Printf("使用'%%T' %T\n", profile)// 使用'%+v' &{Name:stat HP:150}// 使用'%#v' &struct { Name string; HP int }{Name:"stat", HP:150}// 使用'%T' *struct { Name string; HP int }

base64编码解码示例

package mainimport ("fmt""encoding/base64"
)func main() {// 需要处理的字符串message := "Away from keyboard. https://golang.org/"// 编码消息, 传入的字符串需转为字节数组,才能供这个函数使用encodeMessage := base64.StdEncoding.EncodeToString([]byte(message))// 输出编码完成的消息fmt.Println(encodeMessage)// 解码消息data, err := base64.StdEncoding.DecodeString(encodeMessage)// 出错处理if err != nil {fmt.Println(err)} else {fmt.Println(string(data))}// QXdheSBmcm9tIGtleWJvYXJkLiBodHRwczovL2dvbGFuZy5vcmcv// Away from keyboard. https://golang.org/}

七、枚举

7.1 枚举 – 一组常量值

// 使用iota模拟枚举type Weapon intconst (Arrow Weapon = iota // 开始生成枚举值,默认为0ShurikenSniperRifleRifleBlower)// 输出所有枚举值fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)var weapon Weapon = Blowerfmt.Println(weapon)// 0 1 2 3 4// 4

7.2 枚举–将枚举值转换为字符串

package main
import ("fmt")// 声明芯片类型
type ChipType intconst (None ChipType = iotaGPUCPU
)func (c ChipType) String() string {switch c {case None:return "None"case GPU:return "GPU"case CPU:return "CPU"}return "N/A"}func main() {// 输出CPU的值并以整型格式显示fmt.Printf("%s %d", CPU, CPU)//CPU 2
}

八、 类型别名

8.1 区分类型别名与类型定义

类型别名的写法:

type TypeAlias = Type

类型别名规定:

TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型

// 将NewInt定义为int类型
type NewInt int
// 将int取一个别名叫IntAlias
type IntAlias = int// 将a声明为一个NewInt类型
var alias_a NewInt
fmt.Printf("a type: %T\n", alias_a)
// a type: main.NewInt// 将a2声明为IntAlias类型
var alias_a2 IntAlias
fmt.Printf("a2 type: %T\n", alias_a2)// a2 type: int 

8.2 非本地类型不能定义方法

不能为不在同一个包中声明的类型定义方法,即不能为在其他包声明的类型在本地包中定义方法

package mainimport ("time")// 2.8.2
// 定义time.Duration 的别名为MyDuration
type MyDuration = time.Duration// 为MyDuration 添加一个函数
func (m MyDuration) EasySet(a String) {}func main() {}
//# 2-base/2.2-data_type
//.\data_type.go:51:6: cannot define new methods on non-local type time.Duration
//.\data_type.go:51:31: undefined: String
//exit status 2
//Process exiting with code: 1

8.3 在结构体成员嵌入时使用别名

package mainimport ("fmt""reflect"
)// 定义商标结构
type Brand struct {}
// 为商标结构添加Show()方法
func (t Brand) Show() {}// 为Brand定义一个别名
type FakeBrand = Brand
// 定义车辆结构,嵌入商标结构
type  Vehicle struct {BrandFakeBrand
}func main() {// 声明变量 a 为车辆类型var a Vehicle// 指定调用FakeBrand的Showa.FakeBrand.Show()// 取a的类型反射对象ta := reflect.TypeOf(a)// 遍历a的所有成员for i := 0; i < ta.NumField(); i++ {// ta 成员信息f := ta.Field(i)// 打印成员的字段名和类型fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.Name())}// FieldName: Brand, FieldType: Brand// FieldName: FakeBrand, FieldType: Brandgo
}

总结:

  • FakeBrand是Brand的一个别名,在Vehicel中嵌入FakeBrand和Brand,Vehicel的类型会以名字的方式保留在Vehicle的成员中
  • FakeBrand和Brand 都有Show()方法, 调用时必须制定调用谁的, a.FakeBrand.Show()

九、条件语句

8.1 if语句

if 语句由布尔表达式后紧跟一个或多个语句组成。

语法

Go 编程语言中 if 语句的语法如下:

if 布尔表达式 {/* 在布尔表达式为 true 时执行 */
}

注意:if语句一定要加{}

8.2 if…else语句

if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。

语法

Go 编程语言中 if…else 语句的语法如下:

if 布尔表达式 {/* 在布尔表达式为 true 时执行 */
} else {/* 在布尔表达式为 false 时执行 */
}

注意:每一个 if else 都需要加入括号 同时 else 位置不能在新一行

寻找到 100 以内的所有的素数:

package mainimport "fmt"
func main(){// var count,c int   //定义变量不使用也会报错var count intvar flag boolcount=1//while(count<100) {    //go没有whilefor count < 100 {count++flag = true;//注意tmp变量  :=for tmp:=2;tmp<count;tmp++ {if count%tmp==0{flag = false}}// 每一个 if else 都需要加入括号 同时 else 位置不能在新一行if flag == true {fmt.Println(count,"素数")}else{continue}}
}

8.3 switch case语句:

普通的switch语句:

var i = 0
switch i {
case 0:
case 1:fmt.Println(1)
case 2:
fmt.Println(2)
default:fmt.Println(“def”)
}

fallthrough语句:

var i = 0
switch i {
case 0:fallthrough
case 1:fmt.Println(“1”)
case 2:
fmt.Println(“2”)
default:fmt.Println(“def”)
}

注:加了fallthrough后,会直接运行【紧跟的后一个】case或default语句,不论条件是否满足都会执行,后面的条件并不会再判断了。

注意:Go 没有三目运算符,所以不支持***?😗* 形式的条件判断。

十、for循环

for 循环是一个循环控制结构,可以执行指定次数的循环。

语法

Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

和 C 语言的 for 一样:

for init; condition; post { }

和 C 的 while 一样:

for condition { }

和 C 的 for(;😉 一样:

for { }
  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。

for语句执行过程如下:

  • 1、先对表达式 1 赋初值;
  • 2、判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap {newMap[key] = value
}

实例

计算 1 到 10 的数字之和:

实例

package mainimport "fmt"func main() {sum := 0for i := 0; i <= 10; i++ {sum += i}fmt.Println(sum)
}

输出结果为:

55

init 和 post 参数是可选的,我们可以直接省略它,类似 While 语句。

以下实例在 sum 小于 10 的时候计算 sum 自相加后的值:

实例

package mainimport "fmt"func main() {sum := 1for ; sum <= 10; {sum += sum}fmt.Println(sum)// 这样写也可以,更像 While 语句形式for sum <= 10{sum += sum}fmt.Println(sum)
}

输出结果为:

16
16

无限循环:

实例

package mainimport "fmt"func main() {sum := 0for {sum++ // 无限循环下去}fmt.Println(sum) // 无法输出
}

要停止无限循环,可以在命令窗口按下ctrl-c

For-each range 循环

这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。

实例

package main
import "fmt"func main() {strings := []string{"google", "runoob"}for i, s := range strings {fmt.Println(i, s)}numbers := [6]int{1, 2, 3, 5}for i,x:= range numbers {fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)} 
}

以上实例运行输出结果为:

0 google
1 runoob
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0

十一、数组

11.1 声明数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var variable_name [SIZE] variable_type

以上为一维数组的定义方式。例如以下定义了数组 balance 长度为 10 类型为 float32:

var balance [10] float32

11.2 初始化数组

以下演示了数组初始化:

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

初始化数组中 {} 中的元素个数不能大于 [] 中的数字。

如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:

 var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

该实例与上面的实例是一样的,虽然没有设置数组的大小。

 balance[4] = 50.0

以上实例读取了第五个元素。数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为 0,第二个索引为 1,以此类推。

img


11.3 访问数组元素

数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:

var salary float32 = balance[9]

11.4多维数组

Go 语言支持多维数组,以下为常用的多维数组声明方式:

var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

以下实例声明了三维的整型数组:

var threedim [5][10][4]int

11.5初始化多维数组

多维数组可通过大括号来初始值。以下实例为一个 3 行 4 列的二维数组:

a = [3][4]int{  {0, 1, 2, 3} ,   /*  第一行索引为 0 */{4, 5, 6, 7} ,   /*  第二行索引为 1 */{8, 9, 10, 11},   /* 第三行索引为 2 */
}

**注意:**以上代码中倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行,也可以写成这样:

a = [3][4]int{  {0, 1, 2, 3} ,   /*  第一行索引为 0 */{4, 5, 6, 7} ,   /*  第二行索引为 1 */{8, 9, 10, 11}}   /* 第三行索引为 2 */

11.6 访问多维数组

多维数组通过指定坐标来访问。如数组中的行索引与列索引,例如:

val := a[2][3]var value int = a[2][3]

以上实例访问了二维数组 val 第三行的第四个元素。

十二、函数

函数是基本的代码块,用于执行一个任务。

Go 语言最少有个 main() 函数。

你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。

函数声明告诉了编译器函数的名称,返回类型,和参数。

Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。


12.1 函数定义

Go 语言函数定义格式如下:

func function_name( [parameter list] ) [return_types] {函数体
}

函数定义解析:

  • func:函数由 func 开始声明

  • function_name:函数名称,函数名和参数列表一起构成了函数签名。

  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。

  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。

  • 函数体:函数定义的代码集合。

    注意:

    1.2.1 golang函数不支持重载,一个包不能有两个函数名一样的函数。

    1.2.2 函数也是一种类型,一个函数可以赋值给变量。

12.2 函数返回多个值

Go 函数可以返回多个值,例如:

package mainimport "fmt"func swap(x, y string) (string, string) {return y, x
}func main() {a, b := swap("Google", "Runoob")fmt.Println(a, b)
}

以上实例执行结果为:

Runoob Google

12.3 函数return值的几种情况

分三种情况

(以下 “指定返回值”这句话, 仅指return后面直接跟着的返回值)

1.退出执行,不指定返回值
(1) 函数没有返回值

package main
import ("fmt"
)func GetMoney(){
fmt.Println("money")return
}func main(){GetMoney()
}

(2) 函数返回值有变量名

package main
import ("fmt"
)func GetMoney() (_amount int){_amount = 88fmt.Println("money: ",_amount)return
}func main(){var amount  = GetMoney()fmt.Println("money: ",amount)
}

2.退出执行,指定返回值

package main
import ("fmt"
)func GetMoney() (_amount int){fmt.Println("money: ",_amount)return 88
}func main(){var amount  = GetMoney()fmt.Println("money: ",amount)
}运行结果:
money:  0
money:  88

3.退出执行,指定返回值和指定默认值

package main
import ("fmt"
)func GetMoney() (_amount int){
_amount  = 99     //如果return后面没有指定返回值,就用赋给“返回值变量”的值fmt.Println("money: ",_amount)return 88       //如果return后面跟有返回值,就使用return后面的返回值
}func main(){var amount  = GetMoney()  fmt.Println("money: ",amount)
}运行结果:
money:  99
money:  88

12.4 可变参数

  • 0或多个参数
func add(arg…int) int {
}
  • 1或多个参数
func add(a int, arg…int) int {
}
  • 2或多个参数
func add(a int, b int, arg…int) int {
}

12.5 匿名函数

由一个不带函数名的函数声明和函数体组成。

func main()  {i := 1go func(i int) {time.Sleep(100*time.Millisecond)fmt.Println("i =", i)} (i)i++time.Sleep(1000*time.Millisecond)
}

十三、defer的用途

  • 当函数返回时,先执行return,后执行defer语句。因此,可以用来做资源清理、关闭句柄、锁的释放、数据库连接释放。
  • 多个defer语句,按先进后出的方式执行。
  • defer语句中的变量,在defer声明时就决定了。
 func a() {i := 0defer fmt.Println(i)i++return
} 

关闭文件句柄:

func read() {file := open(filename)defer file.Close()//其他操作
}

锁资源的释放:

func read() {mc.Lock()defer mc.Unlock()//其他操作
}

数据库连接释放:

func read() {conn := openDatabase()defer conn.Close()//其他操作
}

十四、输入的使用

1、输入的使用

第一种写法:fmt.Scanf("%d", &a)

第二种写法:fmt.Scan(&a)

示例:

package main //必须有一个main包import "fmt"func main() {var a int //声明变量fmt.Printf("请输入变量a: ")//阻塞等待用户的输入//fmt.Scanf("%d", &a) //别忘了& fmt.Scan(&a)fmt.Println("a = ", a)
}

#执行结果:

请输入变量e:666
a =  666

Scanf %d只能接收整型,不能接收字符型

所以在输入字符型变量时应该使用fmt.Scanf(“%c”,&a)

格式含义
%%一个%字面量
%b一个二进制整数值(基数为2),或者是一个(高级的)用科学计数法表示的指数为2的浮点数
%c字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
%d一个十进制数值(基数为10)
%f以标准记数法表示的浮点数或者复数值
%o一个以八进制表示的数字(基数为8)
%p以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示
%q使用Go语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字
%s字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符)
%t以true或者false输出的布尔值
%T使用Go语法输出的值的类型
%x以十六进制表示的整型值(基数为十六),数字a-f使用小写表示
%X以十六进制表示的整型值(基数为十六),数字A-F使用小写表示

关闭文件句柄:

func read() {file := open(filename)defer file.Close()//其他操作
}

锁资源的释放:

func read() {mc.Lock()defer mc.Unlock()//其他操作
}

数据库连接释放:

func read() {conn := openDatabase()defer conn.Close()//其他操作
}

十四、输入的使用

1、输入的使用

第一种写法:fmt.Scanf("%d", &a)

第二种写法:fmt.Scan(&a)

示例:

package main //必须有一个main包import "fmt"func main() {var a int //声明变量fmt.Printf("请输入变量a: ")//阻塞等待用户的输入//fmt.Scanf("%d", &a) //别忘了& fmt.Scan(&a)fmt.Println("a = ", a)
}

#执行结果:

请输入变量e:666
a =  666

Scanf %d只能接收整型,不能接收字符型

所以在输入字符型变量时应该使用fmt.Scanf(“%c”,&a)

格式含义
%%一个%字面量
%b一个二进制整数值(基数为2),或者是一个(高级的)用科学计数法表示的指数为2的浮点数
%c字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
%d一个十进制数值(基数为10)
%f以标准记数法表示的浮点数或者复数值
%o一个以八进制表示的数字(基数为8)
%p以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示
%q使用Go语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字
%s字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符)
%t以true或者false输出的布尔值
%T使用Go语法输出的值的类型
%x以十六进制表示的整型值(基数为十六),数字a-f使用小写表示
%X以十六进制表示的整型值(基数为十六),数字A-F使用小写表示

http://chatgpt.dhexx.cn/article/j29AKWrg.shtml

相关文章

【Mark】计算机组成原理

Contents 计算机系统概论&#xff08;贯穿本书&#xff09;计算机的发展及应用&#xff08;非重点&#xff09;系统总线存储器高速缓冲存储器 计算机的运算方法指令系统 链接 【超详细】计算机组成原理总结及思维导图. 链接 计算机组成原理知识点. 链接 计算机组成原理----思维…

54_集合类库(上)

集合类库&#xff08;上&#xff09; 集合的概述&#xff08;重点&#xff09; 集合的由来 当需要在Java程序中记录单个数据内容时&#xff0c;则声明一个变量&#xff0c;本质就是在内存中申请一个小格子&#xff0c;把数据塞进去。当需要在Java程序中记录多个类型相同的数据内…

[车联网安全自学篇] Android安全之ARM汇编指令集手册「精简汇总版」

也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 0x01 ARM 指令 1.1 ARM架构的CPU简介 PC端领域CPU的老大是Intel,而移动设备CPU老大就是ARM。不同的cpu架构对应不同的指令集…

论文的排版技巧

在任意中间一页开始插入页码 1.在要插入页码的前一页&#xff0c;插入“分页符”&#xff0c;“插入”-->“分隔符”&#xff0c;选择“分节符类型”中的下一页&#xff0c;如图。 2.在要插入页码的页面&#xff0c;选择“视图”-->“页眉与页角” 去掉“链接到前一个的标…

软件开发实训(720科技)――第五课:前端css规范

一、文件规范 1、文件均归档至约定的目录中。 具体要求通过豆瓣的CSS规范进行讲解&#xff1a; 所有的CSS分为两大类&#xff1a;通用类和业务类。通用的CSS文件&#xff0c;放在如下目录中&#xff1a; 基本样式库 /css/core 通用UI元素样式库 /css/lib JS组件相关样式库 …

word 参考文献插入整理

参考文献插入 方法一&#xff1a;使用尾注插入参考文献 1.1. 以尾注的方式插入第一个参考文献 将光标定位于word文档中将要插入参考文献的位置&#xff0c;按“插入/引用/脚注和尾注”。出现一菜单&#xff0c;选择“尾注”&#xff0c;“文档结尾”&#xff0c;编号格式为“1,…

Word 2010如何对论文中参考文献进行标注

Word 2010如何对论文中参考文献进行标注 1.参考文献在论文中进行标注1.1添加标注1.2修改标注“1→[1]” 2.删除参考文献留下的横线3.参考文献对齐参考 在文章中标注参考文献&#xff0c;之前看别人论文进行的参考文献引文标注&#xff0c;感觉特别高级&#xff0c;这项技能早晚…

WORD 常用操作技巧

word2010首页、目录、正文页码设置方法 2013-07-18 12:11:05| 分类&#xff1a; 实用技巧|举报|字号 订阅 引文来源&#xff1a;http://www.hangxyz.com/display-different-page-number-in-word2010.html 欲在线预览或下载完整教程请访问SkyDrive页面 在用Word编辑说明书、计…

利用Word实现交叉引用或引用尾注添加参考文献图解

from&#xff1a;http://www.office68.com/word/word-reference-add.html 1 利用“交叉引用”加参考文献 1 输入参考文献&#xff0c;如下图 2 选中所有文献&#xff0c;为所选文献统一编号&#xff0c;如下图 3 在正文中需要添加参考文献处添加交叉引用&#xff0c;如下图 4相…

标明文献引用及文献列表自动生成(尾注交叉引用)

摘要&#xff1a; 本文介绍利用Word尾注来注明文献引用&#xff0c;并用交叉引用自动生成文献列表&#xff0c;为论文撰写带来极大便利。最后给出参考文献格式。 撰写论文(或者开题报告或者文献综述)需要在文中标明引用&#xff0c;并生成参考文献列表。一种效率低下的方法&…

word2016用尾注引用参考文献

目录 一、添加参考文献尾注 二、为尾注添加方括号 三、去除尾注横线 四、连续参考文献编号&#xff0c;将[1][2][3]变为[1-3] 五、添加方括号后新增参考文献尾注方括号修改方法 六、多个位置引用同一篇参考文献 一、添加参考文献尾注 1.引用-->尾注栏右下角箭头处-->修…

论文参考文献添加---word尾注添加

论文参考文献添加—word尾注添加 坏坏dong小姐 对于广大毕业生童鞋在写毕业论文的时候&#xff0c;最后加参考文献的时候是不是很头疼&#xff1f;格式问题&#xff0c;序号问题。本文通过word2016尾注功能添加参考文献&#xff0c;方便实用。我希望我的实际操作经验能给大家带…

miniUI设置输入框禁止输入和开启

背景&#xff1a; 用 input标签 enabled"false" 属性设置为禁止输入后js怎么也不开开启输入 错误中的尝试&#xff1a; 解决办法 使用miniUI获取对象&#xff0c;并设置属性就好了 解决代码&#xff1a;

java学习笔记(三):前端miniUI控件库入门

java学习笔记(三)&#xff1a;前端miniUI控件库入门 最近在一家公司实习学习&#xff0c;一上来就需要学习了解相关的前端内容——miniUI。而这个内容自己本身并没有了解学习过&#xff0c;上手也是遇到了不少的问题&#xff0c;于是想把自己刚入门的学习经验来分享记录一下。…

【CubeIDE】MiniUI驱动ili9341液晶屏教程

0x00 前言 MiniUI是笔者为一位非常要好的朋友兼师父基于C开发的屏幕驱动框架&#xff0c;MiniUI分为两部分&#xff08;如图&#xff09;&#xff0c;抽象层&#xff08;Abstract layer&#xff09;继承了底层驱动操作LCD的基础API&#xff0c;例如画点&#xff08;DrawPixel&…

Jquery miniUI 开发教程(2) 搭建Jquery miniUI 开发环境

Jquery miniUI 下载地址&#xff1a;http://www.miniui.com/download Note&#xff1a;请根据不同的服务端后台&#xff0c;选择下载不同后台版本的MiniUI。 下载后&#xff0c;解压缩后&#xff0c;如图所示&#xff1a; 各目录文件解释如下&#xff1a; dbsql&#xff1a;示…

mysql 表格控件,jQuery MiniUI 开发教程 表格控件 表格:分页查询(一)

数据表格 参考示例&#xff1a;数据表格 分页表格 一&#xff1a;创建表格 url"../data/DataService.aspx?methodSearchEmployees" idField"id" allowResize"true" > 员工帐号 姓名 性别 薪资 年龄 创建日期 二&#xff1a;数据加载 条件…

MiniUI快速入门教程(二)编写第一个MiniUI程序:Hello, world!

我们开始编写第一个MiniUI程序&#xff0c;代码如下&#xff1a; <!DOCTYPE html /> <html> <head><title> Hello MiniUI!</title><!--jQuery js--><script src"../jquery.js" type"text/javascript"></scri…

MiniUI快速入门教程(五)主框架布局

下面实现一个最典型主框架布局。 效果图如下&#xff1a; 一&#xff1a;创建界面布局 <!--Layout--> <div id"layout1" class"mini-layout" style"width:100%;height:100%;"><div class"header" region"north&qu…

MiniUI快速入门教程(四)表单开发

表单开发包括&#xff1a;布局、验证、加载、提交、清除、重置等。 效果图如下&#xff1a; 表单布局 使用HTML Table标签实现任意丰富的表单布局&#xff1a; <table class"form-table" border"0" cellpadding"1" cellspacing"2"&…