

2007 年,谷歌工程师 Rob Pike, Ken Thompson 和 Robert Griesemer 开始设计一门全新的语言,这是 Go 语言的最初原型。
2009 年 11 月 10 日,Google 将 Go 语言以开放源代码的方式向全球发布。
2015 年 8 月 19 日,Go 1.5 版发布,本次更新中移除了”最后残余的 C 代码”
2017 年 2 月 17 日,Go 语言 Go 1.8 版发布。
2017 年 8 月 24 日,Go 语言 Go 1.9 版发布。 1.9.2 版本
2018 年 2 月 16 日,Go 语言 Go 1.10 版发布。
Go 语言保证了既能到达静态编译语言的安全和性能,又达到了动态语言开发维护的高效率 ,使用一个表达式来形容 Go 语言:Go = C + Python , 说明 Go 语言既有 C 静态语言程序的运行速度,又能达到 Python 动态语言的快速开发。
等,也保留了和 C 语言一样的编译执行方式及弱化的指针
举一个案例(体验):
//go 语言的指针的使用特点(体验)
func testPtr(num *int) {
*num = 20
}
package main //一个文件都要归属于一个包
import "fmt"
func main() {
fmt.Println("hello word")
}
之间的相互通信。
//写一个函数,实现同时返回 和,差
//go 函数支持返回多个值
func getSumAndSub(n1 int, n2 int) (int, int ) {
sum := n1 + n2 //go 语句后面不要带分号.
sub := n1 - n2
return sum , sub
}
我使用的是GoLand开发工具,比较顺手
GoLand 是 JetBrains 公司推出的 Go 语言集成开发环境。GoLand 同样基于 IntelliJ 平台开发,支持 JetBrains 的插件体系。
下载地址:https://www.jetbrains.com/go/download/other.html
自己选择喜欢的版本和相应的系统下载,不建议使用太新的版本,我自己用2021.3.5版本比较顺手
账号的话可以去淘宝买教育注册渠道,注册后可以使用一年
或者使用插件无限使用30天(⚠️注意21年及之前的可以使用,相对新的版本不支持),相关文档地址:https://blog.csdn.net/qq_37699336/article/details/116528062
SDK 下载地址:Golang 中国 https://www.golangtc.com/download
sdk配置相关参考文档:https://blog.csdn.net/m0_49589654/article/details/127259754
创建一个项目,选择好sdk的路径就可以了

右击项目文件创建一个go file


之后写个hello word
package main //一个文件都要归属于一个包
import "fmt"
func main() {
fmt.Println("hello word")
}
运行

则报错
Golang 官方网站(可能访问不了): https://golang.org
Golang 中文网 在线标准库文档: https://studygolang.com/pkgdoc
概念:变量相当于内存中一个数据存储空间的表示,你可以把变量看做是一个房间的门牌号,通过门牌号我们可以找到房间,同样的道理,通过变量名可以访问到变量 (值)。
变量的使用步骤:声明变量(也叫:定义变量) -> 非变量赋值 -> 使用变量
package main
import "fmt"
func main() {
//创建变量
var a int
//变量赋值
a = 10
//使用变量(进行打印)
fmt.Println("a = ", a)
}
运行结果
a = 10
package main
import fmt "fmt"
// /全局变量///
var age, name = 18, "小明"
///全局变量///
func main() {
//创建变量
//变量=变量名+值+数据类型,这一点请大家注意,变量的三要素
//Golang 的变量如果没有赋初值,编译器会使用默认值, 比如 int 默认值 0 string 默认值为空串, 小数默认为 0
///局部变量///
//1、创建变量但 不赋值 使用的默认值(int 默认值为0)
var a int
//使用变量(进行打印)
fmt.Println("a = ", a)
//2、创建变量但不赋予类型,根据值自行判定变量类型(类型推导)
var b = 10
//fmt.Printf格式化输出 %v:输出值, %T:输出值的类型 \n:换行
fmt.Printf("b = %v, type: %T \n", b, b)
//3、使用:=声明变量
//c := "Go" 等价于 var c string = "Go";
c := "Go"
fmt.Printf("c = %v, type: %T \n", c, c)
//4、多变量声明,带值声明或者不带值声明
var d, e, f int //不带值
var d1, e1, f1 int = 1, 2, 3 //带值(相同类型)
d2, e2, f2 := 1, "123", 's' //带值(相同类型)
fmt.Println(d, e, f, "------", d1, e1, f1, "------", d2, e2, f2)
//注意⚠️:在同一代码块中,不能对类型再次赋予类型
//var testA int = 10;
//testA := 20; // ❌
///局部变量///
//输出全局变量
fmt.Println(age, name)
}
运行结果
a = 0
b = 10, type: int
c = %!d(string=Go), type: string
0 0 0 ------ 1 2 3 ------ 1 123 115
18 小明

| 类型 | 描述 |
|---|---|
| uint | 32位或64位 |
| uint8 | 无符号 8 位整型 (0 到 255) |
| uint16 | 无符号 16 位整型 (0 到 65535) |
| uint32 | 无符号 32 位整型 (0 到 4294967295) |
| uint64 | 无符号 64 位整型 (0 到 18446744073709551615) |
| int | 32位或64位 |
| int8 | 有符号 8 位整型 (-128 到 127) |
| int16 | 有符号 16 位整型 (-32768 到 32767) |
| int32 | 有符号 32 位整型 (-2147483648 到 2147483647) |
| int64 | 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
| byte | uint8的别名(type byte = uint8) |
| rune | int32的别名(type rune = int32),表示一个unicode码 |
| uintptr | 无符号整型,用于存放一个指针是一种无符号的整数类型,没有指定具体的bit大小但是足以容纳指针。 |
| uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。 | |
| float32 | IEEE-754 32位浮点型数 |
| float64 | IEEE-754 64位浮点型数 |
| complex64 | 32 位实数和虚数 |
| complex128 | 64 位实数和虚数 |
整型数据
分为两类,有符号和无符号两种类型
有符号: int, int8, int16, int32, int64
无符号: uint, uint8, uint16, uint32, uint64, byte
不同位数的整型区别在于能保存整型数字范围的大小;
有符号类型可以存储任何整数,无符号类型只能存储自然数
int和uint的大小和系统有关,32位系统表示int32和uint32,如果是64位系统则表示int64和uint64
byte与uint8类似,一般用来存储单个字符
在保证程序正确运行下,尽量使用占用空间小的数据类型
fmt.Printf(“%T”, var_name)输出变量类型
unsafe.Sizeof(var_name)查看变量占用字节
浮点型也就是小数类型,可以存放小数。比如6.6,-12.34
1、关于浮点数在机器中存放形式的简单说明,浮点数=符号位+指数位+尾数位
2、尾数部分可能丢失,造成精度损失。-123.0000901
3、浮点型的存储分为三部分:符号位+指数位+尾数位,在存储过程中,精度会有丢失
4、golang的浮点型默认为float64类型
5、通常情况下,应该使用float64,因为它比float32更精确
6、0.123可以简写成.123,也支持科学计数法表示:5.1234e2 等价于512.34
Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,也就是说对于传统的字符串是由字符组成的,而Go的字符串不同,它是由字节组成的。
布尔类型也叫做bool类型,bool类型数据只允许取值true或false
bool类型占1个字节
bool类型适用于逻辑运算,一般用于流程控制
字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本
1、字符串一旦赋值了,就不能修改了:在Go中字符串是不可变的。
2、字符串的两种标识形式
指针细节说明:
值类型和引用类型使用特点:
值类型:变量直接存储值,内存通常在栈中分配
引用类型:变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆上分配,当没有任何变量应用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收。
Golang中值类型和引用类型的区分
package main
import (
"fmt"
"strconv"
"unsafe"
)
func main() {
println("----byte类型----")
//Golang 程序中整型变量在使用时,遵守保小不保大的原则,即:在保证程序正确运行下,尽量 使用占用空间小的数据类型。【如:年龄】
//bit: 计算机中的最小存储单位。byte:计算机中基本存储单元。[二进制再详细说] 1byte = 8 bit
var n0 byte = 10
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n0, n0, unsafe.Sizeof(n0))
println("----int类型----")
//int 类型
var n1 int = 20
var n2 int8 = 21
var n3 int16 = 22
var n4 int32 = 23
var n5 int64 = 24
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n1, n1, unsafe.Sizeof(n1))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n2, n2, unsafe.Sizeof(n2))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n3, n3, unsafe.Sizeof(n3))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n4, n4, unsafe.Sizeof(n4))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", n5, n5, unsafe.Sizeof(n5))
println("----float类型----")
//float 类型
var f1 float32 = 30.23748734872346 //会损失精度,如果我们要保存一个精度高的数,则应该选用 float64
var f2 float64 = 21.23748734872346
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", f1, f1, unsafe.Sizeof(f1))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", f2, f2, unsafe.Sizeof(f2))
println("----字符类型----")
//字符类型(英文字母占1 个字节 汉字占3 个字节), 可以直接给某个变量赋一个数字,然后按格式化输出时%c,会输出该数字对应的 unicode 字符
//Go 语 言 的 字 符 使 用 UTF-8 编 码 , 如 果 想 查 询 字 符 对 应 的 utf8 码 值 http://www.mytju.com/classcode/tools/encode_utf8.asp
//不理解utf-8、ASCII和Unicode可以看考这篇文章:https://www.bilibili.com/read/cv16001311/
var c0 int = 's'
var c1 int = '北'
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d, 显示信息=%c \n", c0, c0, unsafe.Sizeof(c0), c0)
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d, 显示信息=%c \n", c1, c1, unsafe.Sizeof(c1), c1)
println("----布尔类型----")
//bool 类型占 1 个字节。适于逻辑运算,一般用于程序流程控制
var flagControl bool = true
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", flagControl, flagControl, unsafe.Sizeof(flagControl))
for i := 0; i < 100; i++ {
if i == 10 {
//do something
flagControl = false
}
if flagControl == false {
fmt.Println("结束循环, i= ", i)
break
}
}
println("----string 类型----")
//字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本
//Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本,这样 Golang 统一使用 UTF-8 编码,中文 乱码问题不会再困扰程序员。
var str string = "测试字符串"
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", str, str, unsafe.Sizeof(str))
//注意⚠️:字符串一旦赋值了,字符串就不能修改了:在 Go 中字符串是不可变的。
//var str1 string = "abc"
//str1[0] = 'c' //❌ 不可取,不可修改里面的内容
//字符串的两种表示形式 (1) 双引号, 会识别转义字符 (2) 反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果 【案例演示】
//方式1
var str2 string = "测试字符串"
//方式2
var str3 string = `
测试字符串表示形式,
我是以字符串的原生形式输出,可以实现防止攻击、输出源代码等效果
var str4 string = "4"
`
//字符串拼接方式 "" + "",当一行字符串太长时,需要使用到多行字符串,可以如下处理
var str5 string = "hello" + "word" + "hello" + "word" + "hello" + "word" +
"test" + "str"
fmt.Println(str2, str3, str5)
println("----指针类型----")
//基本数据类型,变量存的就是值,也叫值类型。 获取变量的地址,用&,比如: var num int, 获取 num 的地址:&num
//指针类型,指针变量存的是一个地址,这个地址指向的空间存的才是值
var i int = 10
//1、ptr是一个指针变量 2、ptr存的是i变量的地址 3、类型是*int
var ptr *int = &i
fmt.Printf("指针存储的值:%v, 类型:%T, 占内存字节数:%d, 指针存储地址指向的值:%d, 指针的地址:%v \n", ptr, ptr, unsafe.Sizeof(ptr), *ptr, &ptr)
println("-----基本数据类型的相互转换----")
基本数据类型的相互转换///
//Golang 和 java / c 不同,Go 在不同类型的变量之间赋值时需要显式转换。也就是说 Golang 中数 据类型不能自动转换。
var int_1 int = 100
var float1 float32 = float32(int_1)
var int_2 int8 = int8(int_1)
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", float1, float1, unsafe.Sizeof(float1))
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", int_2, int_2, unsafe.Sizeof(int_2))
//在转换中,比如将 int64 转成 int8 【-128---127】 ,编译时不会报错,只是转换的结果是按 溢出处理,和我们希望的结果不一样。 因此在转换时,需要考虑范围.
var int_3 int64 = 999
var int_4 int8 = int8(int_3) //转换的时候值溢出
fmt.Printf("值:%v, 类型:%T, 占内存字节数:%d \n", int_4, int_4, unsafe.Sizeof(int_4))
//基本类型和string互转
//方式 1:fmt.Sprintf("%参数", 表达式)
var number1 int = 999
var number2 float64 = 999.999
var bool_1 bool = false
var byte_1 byte = 'a'
var str_1 string
str_1 = fmt.Sprintf("%d", number1)
fmt.Printf("1、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
str_1 = fmt.Sprintf("%f", number2)
fmt.Printf("2、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
str_1 = fmt.Sprintf("%t", bool_1)
fmt.Printf("3、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
str_1 = fmt.Sprintf("%c", byte_1)
fmt.Printf("4、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
//方式 2:使用 strconv 包的函数
var number4 int32 = 888
var number5 float64 = 888.888
var bool_2 bool = false
str_1 = strconv.FormatInt(int64(number4), 10)
fmt.Printf("5、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
//FormatFloat(f float64, fmt byte, prec, bitSize int),参数依次表示为转换的值、转换的格式、保留小数后多少位、是转换成float64还是float32
str_1 = strconv.FormatFloat(number5, 'f', 2, 64)
fmt.Printf("6、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
str_1 = strconv.FormatBool(bool_2)
fmt.Printf("7、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", str_1, str_1, unsafe.Sizeof(str_1))
//string 类型转基本数据类型
var str_2 string = "true"
var bool_3 bool
//strconv.ParseBool返回两个值, _标识忽略返回的第二个值
bool_3, _ = strconv.ParseBool(str_2)
fmt.Printf("8、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", bool_3, bool_3, unsafe.Sizeof(bool_3))
// strconv.ParseFloat()同理
// strconv.ParseInt()同理
// strconv.ParseUint()同理
//注意⚠️事项:在将 String 类型转成 基本数据类型时,要确保 String 类型能够转成有效的数据
//比如 我们可以 把 "123" ,转成一个整数,但是不能把 "hello" 转成一个整数,如果这样做,Golang 直接将其转成 0 , 其它类型也是一样的道理. float => 0 bool => false
var str_4 string = "hello"
var int_5 int64
int_5, _ = strconv.ParseInt(str_4, 10, 64)
fmt.Printf("9、转换后的值:%v, 类型:%T, 占内存字节数:%d \n", int_5, int_5, unsafe.Sizeof(int_5))
}
----byte类型----
值:10, 类型:uint8, 占内存字节数:1
----int类型----
值:20, 类型:int, 占内存字节数:8
值:21, 类型:int8, 占内存字节数:1
值:22, 类型:int16, 占内存字节数:2
值:23, 类型:int32, 占内存字节数:4
值:24, 类型:int64, 占内存字节数:8
----float类型----
值:30.237488, 类型:float32, 占内存字节数:4
值:21.23748734872346, 类型:float64, 占内存字节数:8
----字符类型----
值:115, 类型:int, 占内存字节数:8, 显示信息=s
值:21271, 类型:int, 占内存字节数:8, 显示信息=北
----布尔类型----
值:true, 类型:bool, 占内存字节数:1
结束循环, i= 10
----string 类型----
值:测试字符串, 类型:string, 占内存字节数:16
测试字符串
测试字符串表示形式,
我是以字符串的原生形式输出,可以实现防止攻击、输出源代码等效果
var str4 string = "4"
hellowordhellowordhellowordteststr
----指针类型----
指针存储的值:0x14000126050, 类型:*int, 占内存字节数:8, 指针存储地址指向的值:10, 指针的地址:0x14000120020
-----基本数据类型的相互转换----
值:100, 类型:float32, 占内存字节数:4
值:100, 类型:int8, 占内存字节数:1
值:-25, 类型:int8, 占内存字节数:1
1、转换后的值:999, 类型:string, 占内存字节数:16
2、转换后的值:999.999000, 类型:string, 占内存字节数:16
3、转换后的值:false, 类型:string, 占内存字节数:16
4、转换后的值:a, 类型:string, 占内存字节数:16
5、转换后的值:888, 类型:string, 占内存字节数:16
6、转换后的值:888.89, 类型:string, 占内存字节数:16
7、转换后的值:false, 类型:string, 占内存字节数:16
8、转换后的值:true, 类型:bool, 占内存字节数:1
9、转换后的值:0, 类型:int64, 占内存字节数:8

Golang 对各种变量、方法、函数等命名时使用的字符序列称为标识符 ,凡是自己可以起名字的地方都叫标识符。
,var Num int )
是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能作为标识符使用


运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等


package main
import (
"fmt"
)
func main() {
var num_0 int = 100
var num_1 int = 100
var num_2 int = num_1 + num_0/num_0*num_1
println(num_2)
// 演示 % 的使用
//看一个公式 a % b = a - a / b * b
fmt.Println("10%3=", 10%3)
fmt.Println("-10%3=", -10%3)
fmt.Println("10%-3=", 10%-3)
fmt.Println("-10%-3=", -10%-3)
//i++, i--
var i_0 int8 = 0
i_0++
var i_1 int8 = 0
i_1--
fmt.Printf("i_0 = %d, i_1 = %d \n", i_0, i_1)
//Golang 的自增自减只能当做一个独立语言使用时,不能这样使
/**
var i_3 int = i_0 ++ //❌ 错误用法
if i_0 ++ > 1{} //❌ 错误用法
*/
}

用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个 bool 值

1) &&也叫短路与:如果第一个条件为 false,则第二个条件不会判断,最终结果为 **false **
package main
func main() {
//逻辑运算符
var number_0 int8 = 10
var number_1 int8 = 15
if number_1 == 11 || number_0 < 10 {
println("我是1")
} else if number_1 == 15 && number_0 == 10 {
println("我是2")
} else if !(number_1 == 15) {
println("我是3")
}
}


位运算符这边涉及到计算机相关的知识,忘记的可以补习一下二、八、10、16进制以及原码、反码、补码相关的知识
相关链接:https://blog.csdn.net/asd1358355022/article/details/127898198?spm=1001.2014.3001.5501





在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。
fmt 包的 fmt.Scanln() 或者 fmt.Scanf()
函数信息


package main
import "fmt"
func main() {
var name string
var age int
var address string
//方式1:fmt.Scanln
fmt.Println("请输入姓名")
fmt.Scanln(&name)
fmt.Println("请输入年龄")
fmt.Scanln(&age)
fmt.Println("请输入地址")
fmt.Scanln(&address)
fmt.Printf("姓名:%v, 年龄:%v, 地址:%v \n", name, age, address)
//方式2:fmt.Scanf
println("----------------------")
var name_1 string
var age_1 int
var address_1 string
println("请输入你的姓名、年龄、地址,依次按照空格隔开")
fmt.Scanf("%s %d %s", &name_1, &age_1, &address_1)
fmt.Printf("姓名:%v, 年龄:%v, 地址:%v \n", name_1, age_1, address_1)
}
请输入姓名
测试
请输入年龄
18
请输入地址
北京朝阳区
姓名:测试, 年龄:18, 地址:北京朝阳区
----------------------
请输入你的姓名、年龄、地址,依次按照空格隔开
测试 18 北京朝阳区
姓名:测试, 年龄:18, 地址:北京朝阳区
在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。分为:顺序控制、分支控制、循环控制。
程序从上到下逐行地执行,中间没有任何判断和跳转。
一个案例说明,必须下面的代码中,没有判断,也没有跳转.因此程序按照默认的流程执行,即顺序控制。
如下图所示,程序自上而下执行

执行流程图

分支语句的作用就是满足判断条件进入代码块中执行相应的功能
if else流程控制
Golang 中规定与if匹配的{必须与if和表达式位于同一行,否则会发生编译错误。同样的,else也必须上一个分支的}位于同一行。表达式两边可以省略()。 分为单分支语句、双分支语句、多分支语句
switch case流程控制
除了if关键值,Golang 中还提供了switch语句对大量的值和表达式进行判断,除了支持数值常量,Golang 的 switch 还能对字符串、表达式等复杂情况进行处理。
试,直到匹配为止。
**switch 和 if 的比较 **
总结了什么情况下使用 switch ,什么情况下使用 if
语句,简洁高效。
代码示例
package main
import "fmt"
func main() {
println("-------if else流程控制------")
//流程控制
num := 10
//单分支语句
if num <= 10 {
//满足条件进入流程
fmt.Println("单分支测试")
}
//双分支语句
if num > 10 {
fmt.Println("双分支测试01")
} else {
fmt.Println("双分支测试02")
}
//多分支语句,注意⚠️:双分支语句或者多分支语句执行后只会进入到一个流程当中,代码由上而下执行,只要满足即出流程不会就算是其他分支满足条件也不会进入到分支里
if num > 10 {
fmt.Println("多分支测试01")
} else if num == 10 {
fmt.Println("多分支测试02")
} else {
fmt.Println("多分支测试03")
}
//嵌套语句(在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层分 支外面的分支结构称为外层分支。)
num_01 := 20
if num > 10 {
fmt.Println("多分支测试04")
} else if num == 10 {
if num_01 > 20 {
fmt.Println("嵌套分支测试01")
} else if num_01 == 20 {
fmt.Println("嵌套分支测试02")
}
fmt.Println("分支测试05")
}
println("-------switch case流程控制------")
//switch case流程控制
currentTemperature := 25
switch currentTemperature {
case 10:
fmt.Println("当前天气凉")
case 25:
fmt.Println("当前天气温暖~")
case 40:
fmt.Println("当前天气热死了!")
default:
//以上条件都不符合才会进入这里
fmt.Println("这鬼天气多变!")
}
}
运行结果
如下所示,每一种分支只会在满足条件进入到最先满足条件的分支里执行功能
-------if else流程控制------
单分支测试
双分支测试02
多分支测试02
嵌套分支测试02
分支测试05
-------switch case流程控制------
当前天气温暖~
Golang 的循环体仅提供了for关键字,没有其他语言中提供的while或者do-while形式
语法格式
for 循环变量初始化; 循环条件; 循环变量迭代 {
循环操作(语句)
}
package main
import "fmt"
func main() {
//简单示例,循环10次
for i := 0; i < 10; i++ {
fmt.Println("循环次数 i = ", i)
}
//上述还可以这样写
j := 0
for j < 10 {
fmt.Println("循环次数 j = ", j)
j++
}
}
运行结果
循环次数 i = 0
循环次数 i = 1
循环次数 i = 2
循环次数 i = 3
循环次数 i = 4
循环次数 i = 5
循环次数 i = 6
循环次数 i = 7
循环次数 i = 8
循环次数 i = 9
循环次数 j = 0
循环次数 j = 1
循环次数 j = 2
循环次数 j = 3
循环次数 j = 4
循环次数 j = 5
循环次数 j = 6
循环次数 j = 7
循环次数 j = 8
循环次数 j = 9
都产生困难
package main
import "fmt"
func main() {
println("------break测试-----")
k := 0
for { //等价于 for ; ;
if k >= 10 {
//退出循环
break
}
fmt.Println("循环次数 k = ", k)
k++
}
/continue测试///
println("------continue测试-----")
l := 0
for l < 10 {
if l == 2 {
fmt.Println("我是continue测试, l = ", l)
l++
continue
}
fmt.Println("循环测试, l = ", l)
l++
}
/goto测试///
println("------goto测试-----")
flag := false
if flag == false {
goto label_01
}
println("------goto测试----1-----")
println("------goto测试----2-----")
label_01: //跳转标识,上述输出不会打印
println("------goto测试----3-----")
println("------goto测试----4-----")
/return测试///
println("------return测试-----")
returnTestNum := 0
if returnTestNum == 0 {
println("-----到此为止了!-----")
return
}
println("-----执行动作1-----")
println("-----执行动作2-----")
}
运行结果
------break测试-----
循环次数 k = 0
循环次数 k = 1
循环次数 k = 2
循环次数 k = 3
循环次数 k = 4
循环次数 k = 5
循环次数 k = 6
循环次数 k = 7
循环次数 k = 8
循环次数 k = 9
------continue测试-----
循环测试, l = 0
循环测试, l = 1
我是continue测试, l = 2
循环测试, l = 3
循环测试, l = 4
循环测试, l = 5
循环测试, l = 6
循环测试, l = 7
循环测试, l = 8
循环测试, l = 9
------goto测试-----
------goto测试----3-----
------goto测试----4-----
------return测试-----
-----到此为止了!-----
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
time.Now().UnixNano() 返回当前系统的纳秒数
rand.Seed(time.Now().Unix())
rangerNum := 0
for i := 0; i < 10; i++ {
rangerNum = rand.Intn(100) + 1
fmt.Println(rangerNum)
}
}
和c语言相同,Go语言也提供了数组类型的数据结构,数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
package main
import (
"fmt"
)
func main() {
//创建数组
var arr_0 [4]int = [4]int{1, 2, 3, 4}
var arr_1 = [4]float64{111.000, 222, 333, 444.444}
var arr_2 = [...]bool{false, true, true} // 自行判断长度,中括号里...一个不能少
var arr_3 = [...]byte{1: 'a', 0: 'b', 2: 'c'} // 指定索引和值
fmt.Printf("arr_0= %v, 类型:%T \n", arr_0, arr_0)
fmt.Printf("arr_1= %v, 类型:%T \n", arr_1, arr_1)
fmt.Printf("arr_2= %v, 类型:%T \n", arr_2, arr_2)
fmt.Printf("arr_3= %v, 类型:%T \n", arr_3, arr_3)
}
slice 与 array 接近,但是在新的元素加入的时候可以增加长度。slice 总是指向底层的
一个 array。slice 是一个指向 array 的指针,这是其与 array 不同的地方;slice 是引用
类型,这意味着当赋值某个 slice 到另外一个变量,两个引用会指向同一个 array。例 引 用 类 型 使
如,如果一个函数需要一个 slice 参数,在其内对 slice 元素的修改也会体现在函数调 用 make 创建。
用者中,这和传递底层的 array 指针类似。通过:
sl := make([]in t , 10)
创建了一个保存有 10 个元素的 slice。需要注意的是底层的 array 并无不同。slice 总
是与一个固定长度的 array 成对出现。其影响 slice 的容量和长度。
package main
import "fmt"
func main() {
//数组
array_0 := [...]int{1, 2, 3, 4}
//切片(将数组下标为1到3的数据取出来,不含3)
slice := array_0[1:3]
fmt.Printf("slice 内容:%v \n", slice)
fmt.Printf("数组下标为1的数据为:%v, 数组下标为2的数据为:%v \n", array_0[1], array_0[2])
//通过make创建一个数组,但是过程对我们是不可见的
sl := make([]int, 5)
fmt.Printf("切片sl类型:%T, 数据为:%v, 长度:%v \n", sl, sl, len(sl))
println("-------追加内容测试-------")
//追加数据到切片中,尾部追加
sl = append(sl, 1, 2, 3, 3, 4)
fmt.Printf("尾部追加切片sl类型:%T, 数据为:%v 长度:%v \n", sl, sl, len(sl))
//追加切片到切片中,尾部追加
sl = append(sl, []int{1, 2, 3}...)
fmt.Printf("尾部追加切片后切片sl类型:%T, 数据为:%v 长度:%v \n", sl, sl, len(sl))
//追加数据到切片中,头部追加
sl = append([]int{0, 1, 2}, sl...)
fmt.Printf("头部追加切片sl类型:%T, 数据为:%v 长度:%v \n", sl, sl, len(sl))
println("-------合并内容测试-------")
//合并两个切片内容,注意⚠️:切片相同下标的元素会被合并的元素覆盖
copy(sl, slice)
fmt.Printf("合并后切片sl类型:%T, 数据为:%v 长度:%v \n", sl, sl, len(sl))
strArray_1 := [...]string{"123", "234", "456", "999"}
strArray_2 := [...]string{"111", "222", "333", "888"}
strSlice_1 := strArray_1[0:4]
strSlice_2 := strArray_2[1:4]
fmt.Printf("原有strSlice_1 内容:%v \n", strSlice_1)
fmt.Printf("原有strSlice_2 内容:%v \n", strSlice_2)
copy(strSlice_1, strSlice_2)
fmt.Printf("合并后strSlice_1 内容:%v \n", strSlice_1)
fmt.Printf("合并后strSlice_2 内容:%v \n", strSlice_2)
println("-------删除内容测试-------")
//删除内容
newSlice := []int{1, 2, 3}
newSlice = newSlice[1:] //从下标1开始取所有数据,相当于删除了下标为0(即第一个元素)
fmt.Printf("删除后newSlice 内容:%v \n", newSlice)
//删除尾部元素
newSlice = []int{1, 2, 3, 4, 5, 6, 7, 8}
newSlice = newSlice[0 : len(newSlice)-1] //删除最后一个元素
fmt.Printf("删除后newSlice 内容:%v \n", newSlice)
newSlice = newSlice[0 : len(newSlice)-3] //删除最后3个元素
fmt.Printf("删除后newSlice 内容:%v \n", newSlice)
//进行略复杂删除,使用append删除
newArray_01 := [...]string{"a", "b", "c", "d"}
stringsSlice_01 := append(newArray_01[:2], newArray_01[3]) //删除中间下标为2的元素,公式即append(newArray_01[:i], newArray_01[i + 1]),i= 2,删除多个可以参考
fmt.Printf("删除后newArray_01 内容:%v \n", stringsSlice_01)
//进行略复杂删除,使用copy删除
newArray_02 := [...]string{"e", "f", "g", "h"}
fmt.Printf("%v, ---, %v \n", newArray_02[:2], newArray_02[3:])
//看输出内容加以理解,此处将元素["e", "f"] ["h"] 合并后 变为 ->["h", f],可以看下上面切片合并加以理解
//按照需求切分,此处比较绕,多思考
copyAfterLen := copy(newArray_02[:2], newArray_02[3:])
fmt.Printf("copy 后长度:%v newArray_02内容:%v \n", copyAfterLen, newArray_02)
stringsSlice_02 := newArray_02[:copyAfterLen]
fmt.Printf("删除后newArray_02 内容:%v \n", stringsSlice_02)
}
运行结果
slice 内容:[2 3]
数组下标为1的数据为:2, 数组下标为2的数据为:3
切片sl类型:[]int, 数据为:[0 0 0 0 0], 长度:5
-------追加内容测试-------
尾部追加切片sl类型:[]int, 数据为:[0 0 0 0 0 1 2 3 3 4] 长度:10
尾部追加切片后切片sl类型:[]int, 数据为:[0 0 0 0 0 1 2 3 3 4 1 2 3] 长度:13
头部追加切片sl类型:[]int, 数据为:[0 1 2 0 0 0 0 0 1 2 3 3 4 1 2 3] 长度:16
-------合并内容测试-------
合并后切片sl类型:[]int, 数据为:[2 3 2 0 0 0 0 0 1 2 3 3 4 1 2 3] 长度:16
原有strSlice_1 内容:[123 234 456 999]
原有strSlice_2 内容:[222 333 888]
合并后strSlice_1 内容:[222 333 888 999]
合并后strSlice_2 内容:[222 333 888]
-------删除内容测试-------
删除后newSlice 内容:[2 3]
删除后newSlice 内容:[1 2 3 4 5 6 7]
删除后newSlice 内容:[1 2 3 4]
删除后newArray_01 内容:[a b d]
[e f], ---, [h]
copy 后长度:1 newArray_02内容:[h f g h]
删除后newArray_02 内容:[h]
在 Go 中有 map 类型。map 可以认为是一个用字符串做索引的数
组(在其最简单的形式下)。
//初始化一个map,长度为10
stringStringMap := make(map[string]string, 10)
//向map增加元素
stringStringMap["name"] = "Mir Li"
stringStringMap["age"] = "18"
fmt.Printf("stringMap 内容:%v 类型:%T, 长度:%d \n", stringStringMap, stringStringMap, len(stringStringMap))
//覆盖元素操作
stringStringMap["name"] = "Mir Zhang"
fmt.Printf("stringMap 内容:%v 类型:%T, 长度:%d \n", stringStringMap, stringStringMap, len(stringStringMap))
//删除元素操作
delete(stringStringMap, "age")
fmt.Printf("stringMap 内容:%v 类型:%T, 长度:%d \n", stringStringMap, stringStringMap, len(stringStringMap))
//判断是否存在元素
_, present := stringStringMap["name"]
fmt.Printf("stringStringMap 元素是否存在%v元素:%v \n", "name", present)
//其他初始化方式,初始即赋值
stringIntMap := map[string]int{
"Jan": 31, "Feb": 28, "Mar": 31,
"Apr": 30, "May": 31, "Jun": 30,
"Jul": 31, "Aug": 31, "Sep": 30,
"Oct": 31, "Nov": 30, "Dec": 31,
}
fmt.Printf("stringIntMap 内容:%v 类型:%T, 长度:%d \n", stringIntMap, stringIntMap, len(stringIntMap))
运行内容
stringMap 内容:map[age:18 name:Mir Li] 类型:map[string]string, 长度:2
stringMap 内容:map[age:18 name:Mir Zhang] 类型:map[string]string, 长度:2
stringMap 内容:map[name:Mir Zhang] 类型:map[string]string, 长度:1
stringStringMap 元素是否存在name元素:true
stringIntMap 内容:map[Apr:30 Aug:31 Dec:31 Feb:28 Jan:31 Jul:31 Jun:30 Mar:31 May:31 Nov:30 Oct:31 Sep:30] 类型:map[string]int, 长度:12
定义:为完成某一功能的程序指令(语句)的集合,称为函数。
格式
func (p mytype) funcname(q int) (r,s int) { return 0,0 }
}
.0 关键字 func 用于定义一个函数;
.1 函数可以绑定到特定的类型上。这叫做 接收者。有接收者的函数被称作 method。 第 5 章将对其进行说明;
.2 funcname 是你函数的名字;
.3 int 类型的变量 q 作为输入参数。参数用 pass-by-value 方式传递,意味着它们会
被复制;
.4 变量 r 和 s 是这个函数的 命名返回值。在 Go 的函数中可以返回多个值。参阅
第 28 页的 “多值返回”。如果不想对返回的参数命名,只需要提供类型:(int,int)。
如果只有一个返回值,可以省略圆括号。如果函数是一个子过程,并且没有任何
返回值,也可以省略这些内容;
.5 这是函数体。注意 return 是一个语句,所以包裹参数的括号是可选的。
示例代码
package main
import (
"fmt"
)
func main() {
returnValue_1, returnValue_2 := testFunction(10)
//打印返回值
fmt.Printf("returnValue_1 = %v, returnValue_2 = %v", returnValue_1, returnValue_2)
}
//testFunction:函数名, value:函数入参, b、c:函数执行返回参数
func testFunction(value int) (b int, c int) {
fmt.Println("value = ", value)
return 10, 10
}
运行结果:
value = 10
returnValue_1 = 10, returnValue_2 = 10