【Golang第1~3章:基础】如何安装golang、第一个GO程序、golang的基础
介绍
本人是个菜鸡,这个是在B站上看边看视频边做的笔记,这一章是编程语言的基础
有变量、常量、数据类型、指针、标识符、运算符、流程控制,具体请看【文章目录】
配套视频自己去B站里面搜【go语言】,最高的播放量就是
里面的注释我写的可能不太对,欢迎大佬们指出╰(°▽°)╯
(一).安装Golang
1.下载Golang
https://golang.google.cn/dl/
2.设置golang插件地址为国内
打开cmd
输入 go env -w GOPROXY=https://goproxy.cn,direct
设置插件地址为国内CDN七牛云
查看地址是否更改
go env
go env -w GOBIN=D:/apps/Go/bin
关闭GO111MODULE管理工具,这样引入包的时候会默认获取GOPATH的路径进行引入
go env -w GO111MODULE=off
打开电脑环境变量修改GOPATH
-
GOROOT:GOROOT就是Go的安装目录,(类似于java的JDK)
-
GOPATH:GOPATH是我们的工作空间,保存go项目代码和第三方依赖包
3.Vscode插件安装
按住Ctrl
+Shift
+P
输入Go:Install/Update Tools
(二).第一个go程序
打印字符串,链接符号,单行注释,多行注释,变量,字符串
package main
import "fmt"
func main() {
var hello = "你好!!"
fmt.Println("hello !!!")
fmt.Println(hello)
fmt.Println("你好:" + "hello" + hello)
// 反引号可以强制转换为字符串
str := `
sdfjalsdjf
sdf
func
var hello = "你好!!"
fmt.Println("hello !!!")
\sdf \n sdfinesl
`
fmt.Println(str)
}
// 单行注释
/*
多行注释
*/
字符串的两种表示形式
- 双引号, 会识别转义字符
- 反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果
(三).基础
1.变量
三种声明方式
package main
import "fmt"
func main() {
var i int = 10 // var 变量名 类型 = 值
var j = 1.2 // var 变量名 = 值
name := "szc" // 变量名 := 值,自动推导类型
fmt.Println("i = ", i, ", j = " , j , ", name = ", name)
}
一次声明多个变量,变量名和值一一对应
var a, sex, b = 1, "male", 7
a, sex, b := 2, "male", 4
函数外声明全局变量
var (
n1 = 1
n2 = 2
n3 = 3
)
var n4 = "n4"
func main() {
fmt.Println("n1 = ", n1, ", n2 = ", n2, "n3 = ", n3, ", n4 = ", n4)
}
变量声明后必须使用,而且不能隐式改变类型(int转float)
2.常量
常量必须赋初值,而且不可更改
const tax int = 1
const name_ = "szc"
const b = 4 / 2
// const b_ = getVal() // 编译期值不确定
// num := 1
// const b_ = num / 2 // 编译期值不确定
// const tax_0 int // 必须赋初值
// tax = 2 // 不可修改
常量只能修饰布尔、数值、字符串类型
也可以这么声明常量,可以在函数里面声明
const (
a = iota //0
b = iota //1
c = iota //2
d,e = iota,iota //3 3
)
fmt.Println(a, b, c, d, e) // 0 1 2 3 3 依次加1
上面b和c可以不写= iota,但是a必须写
3.数据类型
- 数值型中的int32又称为rune,可保存一个unicode码点。int和uint的大小和操作系统位数一样,32位OS(系统)则为4字节,64位OS则为8字节。浮点数默认64位,整数默认int。
- float32 精确度为小数点后6位,float64为14位;
值类型与引用类型
值类型:基本数据类型、数组、结构体。变量直接存储值,通常存储于栈中,函数传参时使用值传递
引用类型:指针、切片、映射、管道、接口等。变量存储的是值的地址,通常存储于堆中,会发生GC,函数传参时使用引用传递。
函数参数的两种传递方式:
- 值传递
- 引用传递
不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
查看变量类型
查看变量类型:
a, sex:= 2, "male"
fmt.Printf("a的类型:%T,sex的类型:%T\n", a, sex)
查看变量占用内存大小时,先导入unsafe和fmt包
import (
"fmt"
"unsafe"
)
再调用unsafe.Sizeof函数就行
fmt.Printf("a占用内存大小:%d, sex占用内存大小:%d", unsafe.Sizeof(a), unsafe.Sizeof(sex))
字符与字符串
输出字符时,需要格式化输出,否则会输出的它的ascii值
c1 := 's'
c2 := '0'
fmt.Println("c1 = ", c1, ", c2 = ", c2)
fmt.Printf("c1 = %c, c2 = %c\n", c1, c2)
输出汉字和对应unicode码值
c3 := '宋'
fmt.Printf("c3 = %c, 对应unicode码值: %d\n", c3, c3)
跨行字符串,用`包住
var s = `
拜仁慕尼黑来自德甲。
它在今年欧冠八分之一淘汰赛上首回合客场3:0完胜切尔西。
`
多行拼接字符串,要在+后面换行,而不是字符串后面
s1 := "abc" +
" def" + "hij"
数据类型默认值
%d表示为十进制,%v是变量的原值输出,%f是浮点输出,%T是数据类型
var a int //0
var b float32 //0
var c float64 //0
var isMarried bool //false
var name string //空的
//%d表示为十进制,%v是变量的原值输出,%f是浮点输出,%T是数据类型
fmt.Printf("a=%d,b=%f,c=%f,isMarried=%v,name=%v", a, b, c, isMarried, name)
fmt.Printf("a=%d,b=%v,c=%v,isMarried=%v,name=%v", a, b, c, isMarried, name)
数据相互转换
不同数据类型之间必须显式类型转换
a1 := 1.2
a2 := int(a1)
fmt.Println("a2 = ", a2)
var i int32 = 100
//希望将i => float
var n1 float32 = float32(i)
var n2 int8 = int8(i)
var n3 int64 = int64(i) //低精度->高精度
fmt.Printf("i=%v n1=%v n2=%v n3=%v", i, n1, n2, n3)
如果范围大转换成范围小的,可能会发生精度损失,以下是例子:
var i1 int32 = 12
var i2 int8
var i3 int8
i2 = int8(i1) + 127 // 编译通过,但是运行时溢出,得不到想要结果
i3 = int(i1) + 128 // 直接溢出,编译错误
fmt.Println("i2 = ", i2)
基本数据类型转换为string类型
在程序开发中,我们经常将基本数据类型转成 string,或者将 string 转成基本数据类型。
方式 1:fmt.Sprintf(“%参数”, 表达式)
func main() {
var num1 int = 99
var str string //空的str
//把num1转换为string类型
str = fmt.Sprintf("%d", num1) //%d表示为十进制
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str)
var num2 float64 = 23.456
str = fmt.Sprintf("%f", num2) //%f为浮点数
fmt.Printf("str的类型是%T , str的原值是%v\n", str, str) //%v原值输出
var b bool = true
str = fmt.Sprintf("%t", b) //%t布尔值true或false
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str) //%q表示字符串输出并加上引号,同%v
var myChar byte = 'h'
str = fmt.Sprintf("%c", myChar) //%c表示为字符,转换为字符串
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str)
}
输出为
str的类型是string , str的原值是"99"
str的类型是string , str的原值是23.456000 //这个没有按%q输出,所以没有双引号
str的类型是string , str的原值是"true"
str的类型是string , str的原值是"h"
方式 2:使用 strconv 包的函数
用之前先导入strconv包
import (
"fmt"
"strconv"
)
然后调用函数进行转换
var num3 int = 99
var num4 float64 = 23.456
var b2 bool = true
str = strconv.FormatInt(int64(num3), 10)
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str)
// strconv.FormatFloat(num4, 'f', 10, 64)
// 说明: 'f' 转换的格式,10:表示小数点保留10位,64:表示这个小数是float64
str = strconv.FormatFloat(num4, 'f', 10, 64)
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str)
str = strconv.FormatBool(b2)
fmt.Printf("str的类型是%T , str的原值是%q\n", str, str)
string类型转换为基本数据类型
func main() {
var str string = "true"
var b bool
// b, _ = strconv.ParseBool(str)
// 说明
// 1. strconv.ParseBool(str)函数会返回两个值(value bool, err error)
// 2. 因为我只想获取到value bool ,不想获取err 所以使用 _ 忽略
b, _ = strconv.ParseBool(str)
fmt.Printf("b的数据类型是%T , b的值为%v\n\n", b, b)
var str2 string = "12331"
var n1 int64
var n2 int
n1, _ = strconv.ParseInt(str2, 10, 64)
n2 = int(n1)
fmt.Printf("n1的数据类型是%T , n1的值为%v\n", n1, n1)
fmt.Printf("n2的数据类型是%T , n2的值为%v\n\n", n2, n2)
var str3 string = "12331.1321"
var f1 float64
f1, _ = strconv.ParseFloat(str3, 64)
fmt.Printf("f1的数据类型是%T , f1的值为%v\n", f1, f1)
}
输出为
b的数据类型是bool , b的值为true
n1的数据类型是int64 , n1的值为12331
n2的数据类型是int , n2的值为12331
f1的数据类型是float64 , f1的值为12331.1321
说明
string 转基本数据类型的注意事项
在将 String 类型转成 基本数据类型时,要确保 String 类型能够转成有效的数据,比如 我们可以 把 “123” , 转成一个整数,但是不能把 “hello” 转成一个整数,如果这样做,Golang 直接将其转成 0 , 其它类型也是一样的道理. float => 0 bool => false
指针
-
基本数据类型,变量存的就是值,也叫值类型
-
获取变量的地址,用&,比如:var num int,获取num的地址: &num
-
指针类型,指针变量存的是一个地址,这个地址指向的空间存的才是值 如:
var ptr *int = &num // ptr是指针变量 ptr的类型为 *int 值为&num
-
获取指针类型所指向的值,使用:,比如: var ptr int,使用ptr获取p指向的值
func main() {
//基本数据类型在内存布局
var i int = 10
//i的地址是 &i
fmt.Print("i的内存地址是:", &i, "\n\n")
//下面var ptr *int = &i
//1.ptr 是一个指针的变量
//2.ptr 的类型 *int
//3.ptr 本身的值&i
var ptr *int = &i
fmt.Printf("ptr的值是%v\n", ptr)
fmt.Printf("ptr内存地址:%v\n", &ptr)
fmt.Printf("ptr取本身的i值:%v\n", *ptr)
}
值类型和引用类型
-
值类型:变量直接存储值,内存通常在栈中分配
示意图:
-
引用类型:变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆 上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由 GC 来回收
示意图:
-
内存的栈区和堆区
示意图:
4.标识符
标识符概念
- Golang对各种变量、方法、函数等命名时使用的字符序列称为标识符
- 凡是自己可以起名字的地方都叫标识符
标识符的命名规则
-
由26个英文字母大小写, 0-9, _组成
-
数字不可以开头。
-
Golan中严格区分大小写
-
标识符不能包含空格
-
下划线”_”本身在Go中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能作为标识符使用
-
不能以系统保留关键字作为标识符,比如 break,if 等等
系统保留关键字
下面列出25个Go语言的关键字或保留字:
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 |
除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符,其中包含了基本类型的名称和一些基本的内置函数,见下表:
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
---|---|---|---|---|---|---|---|---|
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
标识符的命名规范
- 包名:保持 package的名字和目录保持一致,包名统一使用单数形式,尽量采取有意义的包名,简短,有意义,不要和标准库冲突
- 变量名、函数名、常量名:采用驼峰法
- 如果变量名、函数名、常量名首字母大写,则可以被其他的包访问;如果首字母小写则只能在本包中使用(注:可以简单的理解成,首字母大写是公有的,首字母是私有的),在 golan没有public, private等关键字
- 文件命名:一律采用小写,不用驼峰式,尽量见名思义,看见文件名就可以知道这个文件下的大概内容。
其中测试文件以_test.go结尾,除测试文件外,命名不出现。
5.运算符
算数运算符
下表列出了所有Go语言的算术运算符。假定 A 值为 10,B 值为 20。
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B 输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
– | 自减 | A– 输出结果 9 |
注:
-
/ 运算符需要保留小数位时需要有浮点型参与运算
-
% 结果计算公式为: a % b = a - a / b * b
-
Golang的自增自诚只能当做一个独立语言使用时,不能这样使 b := a++或者b := a–
-
Golang的++ 和 – 只能写在变量的g后面,不能写在变量的前面,即:只有a++,a–没有++a,–a
-
Golang的设计者去掉c/java中的自增自诚的容易混淆的写法,让 Galang更加简洁,统一 (强制性的)
关系运算符
下表列出了所有Go语言的关系运算符。假定 A 值为 10,B 值为 20。
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
逻辑运算符
下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A || B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A && B) 为 True |
- &&也叫短路与:如果第一个亲件为 False,则第二个条件不会判断,最终结果为 false
- ||叫短路或:如果第一个亲件为true,则第二个条件不会判断,最终结果为true
案例
func test() bool {
fmt.Println("test...")
return true
}
func main() {
var i = 10
// 短路与
// 因为 i < 9 为 false,因此后面的test() 和 hello... 都不执行
// 因为 i > 9 为 true ,结果都为真,所以 test() 和 hello... 都输出
if i < 9 && test() {
fmt.Println("hello...")
}
// 因为 i < 9 为 false,但是test()为true,因此只执行test()
// 因为 i > 9 为 ture 所以 test() 不执行,
if i > 9 || test() {
fmt.Println("hello...")
}
赋值运算符
下表列出了所有Go语言的赋值运算符。假定 A 为21
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A 将 A 赋值给 C,结果:21 |
+= | 相加后再赋值 | C += A 等于 C = C + A,结果:42 |
-= | 相减后再赋值 | C -= A 等于 C = C - A,结果:21 |
*= | 相乘后再赋值 | C *= A 等于 C = C * A,结果:441 |
/= | 相除后再赋值 | C /= A 等于 C = C / A,结果:21 |
%= | 求余后再赋值 | C %= A 等于 C = C % A,结果:0//不记入计算 |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2,结果:84 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2,结果:21 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2,结果:0 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2,结果:2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2,结果:2 |
- 赋值运算符的运算顺序为:从右往左
- 运算符的左边只能是变量,右边可以是变量、表达式、常量
运算符优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 运算符
7 ^ !
6 * / % << >> & &^
5 + - | ^
4 == != < <= >= >
3 <-
2 &&
1 ||
- 只有单目运算符、赋值运算符是从右向左运算的。其余都是从左向右
- 可以通过使用括号来临时提升某个表达式的整体运算优先级。
位运算符
位运算符对整数在内存中的二进制位进行操作。假定 A 为60,B 为13
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符”&”是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
| | 按位或运算符”|”是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或运算符”^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | (A ^ B) 结果为 49, 二进制为 0011 0001 |
<< | 左移运算符”<<”是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<”左边的运算数的各二进位全部左移若干位,由”<<”右边的数指定移动的位数,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移运算符”>>”是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>”左边的运算数的各二进位全部右移若干位,”>>”右边的数指定移动的位数。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
演示示例:
package main
import "fmt"
func main() {
var a int = 60 //二进制是:111100
var b int = 13 //二进制是:001101
fmt.Printf("%b\n%d\n",a&b,a&b) //二进制是:1100,对应的十进制是12。说明&进行的是上下对应位的与操作
fmt.Printf("%b\n%d\n",a|b,a|b) //二进制是:111101,对应的十进制是61。说明&进行的是上下对应位的或操作
fmt.Printf("%b\n%d\n",a^b,a^b) //二进制是:110001,对应的十进制是49。^位运算符是上下对应位不同时,值为1
c := 1 >> 2 //0000 0001 => 0000 0000 = 0
d := 1 << 2 //0000 0001 => 0000 0100 = 4
}
原码,反码,补码
计算机都是以补码运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QtDR1TJM-1668406607764)(assets/image-20220720204124199.png)]
左移右移运算符示例(实现计算器存储单位):
package main
import "fmt"
const (
KB float64 = 1<<(10*iota) //iota是 const 结构里面,定义常量行数的索引器,每个 const 里面,iota 都从 0 开始
MB //下面是一个省略调用,继承了上面的表达式
GB
TB
PB
)
func main() {
fmt.Printf("1MB = %vKB\n",MB)
fmt.Printf("1GB = %vKB\n",GB)
fmt.Printf("1TB = %vKB\n",TB)
fmt.Printf("1PB = %vKB\n",PB)
}
运行结果:
1MB = 1024KB
1GB = 1.048576e+06KB
1TB = 1.073741824e+09KB
1PB = 1.099511627776e+12KB
其他运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a; 将给出变量的实际地址。 |
* | 指针变量。 | *a; 是一个指针变量 |
内存地址和指针的示例:打印变量类型用%T
package main
import "fmt"
func main() {
var a int = 4
var b int32
var c float32
var ptr *int
fmt.Printf("a 变量类型为 = %T\n", a ) //输出变量类型%T
fmt.Printf("b 变量类型为 = %T\n", b )
fmt.Printf("c 变量类型为 = %T\n", c )
ptr = &a
fmt.Printf("a 的内存地址为 = %p",ptr) //go里面的内存块地址通常都是用十六进制表示的,因此输出:0x10414020a
fmt.Printf("*ptr 为 %d\n", *ptr) //这是个指向a的内存地址的指针,因此输出:4
}
特殊说明
举例说明,如果在 golang 中实现三元运算的效果
读取控制台数据
调用fmt.Scan等方法即可
var j string
fmt.Scanln(&j) // Scanln读取一行
fmt.Println("j = ", j)
或者指定输入格式
var j string
var m float32
var n bool
fmt.Scanf("%d%f%s%t", &i, &m, &j, &n)
fmt.Println("i = ", i, "j = ", j, "m = ", m, "n = ", n)
输入时按空格或回车区分即可
6.流程控制
if-else 流程控制
基本语法
if 表达式1 { // 表达式可以写(),官方不推荐写
//代码块
} else if 表达式2{ // else if 可省略,不能换行写
//代码块
} else { // else 可省略,不能换行写
//代码块
}
switch分支结构
基本语法
switch 表达式 {
case 表达式1,表达式2,…… :
// 语句块1
case 表达式3,表达式4,…… :
// 语句块2
// 多个case,结构同上
default :
// 语句块3
}
例子:
var time int
fmt.Println("请输入a,b,c,d,e,f,g")
fmt.Scanf("%c", &time)
switch time {
case 'a':
fmt.Println("星期一")
case 'b':
fmt.Println("星期二")
default:
fmt.Println("输入有误")
}
switch 的执行的流程:
- 先执行表达式,得到值,然后和 case 的表达式进行比较,如果相等,就匹配到,然后执行对应的 case 的语句块,然后退出 switch 控制。
- 如果 switch的表达式的值没有和任何的 case 的表达式匹配成功,则执行 default的语句块。
- 多个表达式使用逗号间隔
for循环
基本语法
for 循环变量初始化 ;循环条件 ;循环变量迭代 {
//循环操作
}
for i := 0 ; i < 10 ; i++ {
//代码块
}
注:Go中没有while,do…while循环,Go语言支持goto跳转,但不支持使用
死循环写法
//写法一
for {
//循环执行语句
}
//写法二
for ;; {
//循环执行语句
}
通常和break使用
break终止循环
break用于终止某个语句块的执行,用于中断当前for或跳出switch语句
break 出现在多层嵌套循环中可以使用标签(label)表明要终止哪个循环
for i := 0 ; i < 4 ; i++ {
for j := 0 ; j < 10 ; j++ {
if j==2 {
break // break 默认会跳出最近的for循环
}
fmt.Println("j=",j)
}
}
输出结果:
j= 0
j= 1
j= 0
j= 1
j= 0
j= 1
j= 0
j= 1
使用标签
label1:
for i := 0 ; i < 4 ; i++ {
for j := 0 ; j < 10 ; j++ {
if j==2 {
break label1 // 一旦触发直接终止i的循环
}
fmt.Println("j=",j)
}
fmt.Println("i=",i)
}
输出结果:
j= 0
j= 1
continue跳过本次循环
continue用于结束本次循环,在多层嵌套时可用标签跳转,用法同上(break是终止循环,continue是跳过本次循环)
for-range遍历
这是一种同时获取索引和值或键值的遍历方式
如果我们的字符串含有中文,那么传统的遍历字符串方式,就是错误,会出现乱码。
原因是传统的 对字符串的遍历是按照字节来遍历,而一个汉字在 utf8 编码是对应 3 个字节。
如何解决 需要要将 str 转成 []rune 切片.=> 体验一把
while 和 do…while 的实现
Go 语言没有 while 和 do…while 语法,这一点需要同学们注意一下,如果我们需要使用类似其它语 言(比如 java / c 的 while 和 do…while ),可以通过 for 循环来实现其使用效果。
func main() {
//使用while方式输出10句hello world!
var i int = 1
for {
if i > 10 {
break
}
fmt.Println("hello world", i)
i++
}
//使用do...while方式输出10句hello ok!
var j int = 1
for {
fmt.Println("hello ok!", j)
j++
if j > 10 {
break
}
}
}
for 循环是一个无限循环
break 语句就是跳出 for 循环
练习题:打印金字塔
package main
import "fmt"
func main() {
//使用 for 循环完成下面的案例请编写一个程序,可以接收一个整数,表示层数,打印出金字
//编程思路
/*
//1,打印一个矩形
***
***
***
//2,打印整个金字塔
* 1层1个* | 规律:2 * 层数 -1 | 空格规律:总层数-当前层数
*** 2层2个* | 规律:2 * 层数 -1 | 空格规律:总层数-当前层数
***** 3层3个* | 规律:2 * 层数 -1 | 空格规律:总层数-当前层数
//3,打印空心金字塔
*
* *
*****
*/
number := 5
for i := 1; i <= number; i++ {
//打印*号前先打印空格
for n := 1; n <= number-i; n++ {
fmt.Print(" ")
}
fmt.Printf(" ")
for j := 1; j <= 2*i-1; j++ {
//判断第一个是打印*号还是空格
if j == 1 || j == 2*i-1 || i == number {
fmt.Print("*")
} else {
fmt.Print(" ")
}
}
fmt.Println()
}
}
break引入和快速入门
生成随机数
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
//为了生成一个随机数,还需要rand设置一个种子
//time.Now().Unix() : 返回一个从1970:01:01 的0时0秒到现在的秒数 ,就是一个时间戳
fmt.Println(time.Now().Unix())
rand.Seed(time.Now().Unix())
//如何随机生成1-100
n := rand.Intn(100) + 1 // [0 100) 不包含100
fmt.Println(n)
}
生成多个随机数演示break退出
var conut int = 0
for {
rand.Seed(time.Now().UnixNano())
n := rand.Intn(100) + 1
fmt.Println(n)
conut++
if n == 99 {
break
}
}
fmt.Println("生成 99 一共使用了", conut)
break 默认会跳出最近的 for 循环
break 后面可以指定标签,跳出标签对应的 for 循环
跳转控制语句-goto
Go 语言的 goto 语句可以无条件地转移到程序中指定的行。
goto 语句通常与条件语句配合使用。可用来实现条件转移,跳出循环体等功能。
在 Go 程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序 都产生困难。
跳转控制语句-return
return 使用在方法或者函数中,表示跳出所在的方法或函数
![](https://img-blog.csdnimg.cn/a94ee9b3dd4f4a4e881846173bbbd509.jpeg)
章节目录
【Golang第1~3章:基础】如何安装golang、第一个GO程序、golang的基础
【Golang第4章:函数】Golang包的引用,return语句、指针、匿名函数、闭包、go函数参数传递方式,golang获取当前时间
【Golang第5章:数组与切片】golang如何使用数组、数组的遍历和、使用细节和内存中的布局;golang如何使用切片,切片在内存中的布局
【Golang第6章:排序和查找】golang怎么排序,golang的顺序查找和二分查找,go语言中顺序查找二分查找介绍和案例
【Golang第7章:map】go语言中map的基本介绍,golang中map的使用案例,go语言中map的增删改查操作,go语言对map的值进行排序
【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态
【Golang第9章:项目练习】go项目练习家庭收支记账软件项目、go项目练习客户管理系统项目
【Golang第10章:文件操作】GO语言的文件管理,go语言读文件和写文件、GO语言拷贝文件、GO语言判断文件是否存在、GO语言Json文件格式和解析
【Golang第12章:goroutine协程与channel管道】GO语言goroutine协程和channel管道的基本介绍、goroutine协