package main
import (
"fmt"
"math"
)
func main01() {
// 定义格式:var 变量名 数据类型 = 值
// int 表示整型数据
var sum int = 100
// 变量在程序运行过程中,值可以发生改变
sum = sum + 50
fmt.Println(sum)
}
func main02() {
// 变量的声明,如果没有赋值,默认值为0
var sum int
// 为变量赋值
sum = 50
fmt.Println(sum)
}
func main03() {
// float64 浮点型数据
var value float64 = 2
// var sum3 float64 = value * value * value * value * value
// 可以使用系统提供的包,计算数据的 n 次方
// 需要导入math包,Pow函数
var sum float64 = math.Pow(value, 5)
fmt.Println(sum)
}
2.2 自动推导类型
package main
import "fmt"
func main() {
// 传统的变量定义方式
// 不同的数据类型在内存中开辟的空间不同
// var a int = 10
// var b float64 = 123.456
// 第一种自动推导类型
// var a = 10
// var b = 123.456
// 第二种自动推导类型(推荐)
a := 10
b := 123.456
// 不同的数据类型不能计算
// c := a + b // err
fmt.Println(a)
fmt.Println(b)
}
2.3 交换变量
package main
import "fmt"
func main() {
//交换两个变量的值
a := 10
b := 20
// 第一种使用第三变量进行交换
// c := a
// a = b
// b = c
// 第二种通过运算进行交换
// a = a + b
// b = a - b
// a = a - b
// 第三种通过多重赋值进行交换(推荐)
a, b = b, a
fmt.Println(a)
fmt.Println(b)
}
2.4 多重赋值和匿名变量
package main
import "fmt"
func main01() {
// 多重赋值
// 变量个数和值的个数要一一对应
a, b, c := 10, 123.456, "golang"
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
func main02() {
var a int = 10
var b int = 20
// 在一个作用域范围内变量名不能重复
// var a = 100
// 使用多重赋值修改变量
//a, b = 100, 200
// 多重赋值时如果有新定义的变量,可以使用自动推导类型,加个冒号
a, b, c, d := 100, 200, "hello", "golang"
// 没有定义新变量时不能使用自动推导类型
//a, b := 100, 200 // err
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
func main() {
// _表示匿名变量 不接收数据
_,_,c,d := 100,200,"hello","golang"
fmt.Println(c)
fmt.Println(d)
}
2.5 格式化输出
格式化输出打印目前需要使用 fmt.Printf() 配合占位符
fmt.Println() 收到非十进制数字都会自动转换成十进制
十六进制数据是以0x开头,例如 0xABC
八进制数据是以0开头,最大值为7,例如 0777
二进制数据不能在go语言中直接表示
package main
import "fmt"
func main() {
// 换行输出
fmt.Println("hello golang")
// 不换行输出
fmt.Print("hello golang")
a, b, c := 10, 123.456, "golang"
// format,格式输出,\n表示一个转义字符换行
// %d是一个占位符,表示输出一个整型数据
fmt.Printf("\n%d", a) // 10
// %f是一个占位符,表示输出一个浮点型数据
// %f默认保留六位小数,因为浮点型数据不是精准的数据,六位是有效的
fmt.Printf("\n%f", b) // 123.456000
// %.2f保留小数位数为两位,会对第三位小数进行四舍五入
fmt.Printf("\n%.2f", b) // 123.46
// %s是一个占位符,表示输出一个字符串类型
fmt.Printf("\n%s", c) // golang
}
package main
import "fmt"
func main01() {
// 声明变量
var a int
// 通过键盘为变量赋值
// & 是一个运算符,取地址运算符
// 输入必须加 & 运算符,简单点理解是修改变量a在内存中储存的值
fmt.Scan(&a)
// fmt.Println(&a) // 内存地址 0xc042058080 是一个十六进制整型数据
fmt.Println(a)
}
func main02() {
// 可以一次声明多个变量
var a, b int
// 空格或回车 表示一个输入接收结束
fmt.Scan(&a, &b)
fmt.Println(a)
fmt.Println(b)
}
func main03() {
var a int
var b string
// 带format格式化的,在接收字符串时只能用空格作为分割
fmt.Scanf("%d%s", &a, &b)
fmt.Printf("%d", a)
fmt.Printf("%s", b)
}
func main() {
//通过键盘输入学生三门成绩计算总成绩和平均成绩
var c, m, e int
fmt.Scan(&c, &m, &e)
sum := c + m + e
fmt.Println("总成绩:", sum)
// 两个整型数据相除 得到的结果也是整型
fmt.Println("平均成绩:", sum/3)
}
2.7 变量命名规范
允许使用字母、数字、下划线
不允许使用go系统关键字
不允许使用数字开头
区分大小写
见名知义
三、基础数据类型
3.1 数据类型汇总
引用类型目前只知道有3个,切片、字典、通道。
类型
名称
长度(字节)
默认值
范围
说明
bool
布尔类型
1
false
其值不为真即为假,不可以用数字代表true或false
byte
字节类型
1
0
0 ~ 255
uint8的别名
rune
字符类型
4
0
-2147483648 ~ 2147483647
int32的一个别名,主要用于表示utf-8编码时的字符类型
uintptr
无符号整型
4或8
无符号整型,用于存放一个指针
uint
无符号整型
4或8
0
32位系统等于int32,64位系统等于int64
uint8
无符号整型
1
0
0 ~ 255
uint16
无符号整型
2
0
0 ~ 65535
uint32
无符号整数类型
4
0
0 ~ 4294967295
小数位精确到7位
uint64
无符号整型
8
0
0 ~ 18446744073709551615
小数位精确到15位
int
整型
4或8
0
32位系统等于int32,64位系统等于int64
int8
整型
1
0
-128 ~ 127
int16
整型
2
0
-32768 ~ 32767
int32
整型
4
0
-2147483648 ~ 2147483647
int64
整型
8
0
-9223372036854775808 ~ 9223372036854775807
float32
单精度浮点型
4
0.0
float64
双精度浮点型
8
0.0
complex64
浮点类型
8
32 位实数和虚数
complex128
浮点类型
16
64 位实数和虚数
array
数组值类型
struct
结构体值类型
string
字符串值类型
“”
UTF-8 字符串
slice
切片
nil
引用类型
map
字典
nil
引用类型
channel
通道
nil
引用类型
interface
接口
nil
function
函数
nil
3.2 bool 布尔类型
默认值为false
bool类型一般用于条件判断
package main
import "fmt"
func main() {
var a bool
fmt.Println(a) // 默认值为false
b := true
fmt.Printf("%T",b) // 输出一个变量对应的数据类型
}
3.3 int 整数类型
int类型会根据操作系统位数不同在内存中占的字节也不同
64位系统就是int64
32位系统就是int32
64位系统中的int不能直接与int64计算,需要类型装换才可计算
int64
等于 -2^63 ~ 2^63-1
因为0占了一位所以最大值要减1
因为负号占了一字节所以只能是63次方
uint64
等于 -2^64+1 ~ 0
因为0占了一位所以最小值要加1
因为符号统一所以是64次方
3.4 float 浮点数类型
float32 仅小数点后5位是精准的
float64 仅小数点后13位是精准的
自动推导类型创建的浮点型变量,默认类型为float64
package main
import "fmt"
func main() {
var a float32 = 123.456
fmt.Printf("%.5f",a) // 小数点后5位之后不再精准
var b float64 = 123.456
fmt.Printf("\n%.13f",b) // 小数点后13位之后不再精准
c := 3.14
fmt.Printf("\n%T", c) // 自动推导类型是float64(双精度)
}
3.5 byte 字符类型
类型 byte 是 uint8 的别名
需要背诵的ASCII编码值
空格 space 对应值为 32
字符 '0' 对应值为 48
字符 'A' 对应值为 65
字符 'a' 对应值为 97
package main
import "fmt"
func main() {
var abc byte = 'a' // 定义变量abc的值为字符a
fmt.Println(abc) // 直接打印是97
fmt.Printf("%c\n", abc) // 必须使用占位符 %c 输出一个字符
// 其实类型 byte 是 uint8 的别名
fmt.Printf("%T\n", abc) // 输出结果为 uint8
// 根据ASCII编码表,将小写字符 a 转换成大写字符 A
fmt.Printf("%c", abc-32) // 输出结果为 A
}
返回 s 中最后一个满足 f(rune) 的字符的字节位置。如果没有满足 f(rune) 的字符,则返回 -1。
24
替换
Replace(s, old, new string, n int) string
返回s的副本,并将副本中的 old 字符串替换为 new字符串,替换次数为n 次,如果 n 为 -1,则全部替换;如果 old 为空,则在副本的每个字符之间都插入一个 new。
25
替换
Map(mapping func(rune) rune, s string) string
将 s 中满足 mapping(rune) 的字符替换为 mapping(rune) 的返回值。如果 mapping(rune) 返回负数,则相应的字符将被删除。
26
切割
Split(s, sep string) []string
以 sep 为分隔符,将 s 切分成多个子切片,结果中不包含 sep 本身。如果 sep 为空,则将 s 切分成 Unicode 字符列表。如果 s 中没有 sep 子串,则将整个 s 作为[]string的第一个元素返回。
27
切割
SplitN(s, sep string, n int) []string
以 sep 为分隔符,将 s 切分成多个子串,结果中不包含 sep 本身。如果 sep 为空则将 s 切分成 Unicode 字符列表。如果 s 中没有 sep 子串,则将整个 s 作为 []string 的第一个元素返回。参数 n 表示最多切分出几个子串,超出的部分将不再切分,最后一个 n 包含了所有剩下的不切分。如果 n 为 0,则返回 nil;如果 n 小于 0,则不限制切分个数,全部切分。
28
切割
SplitAfter(s, sep string) []string
以 sep 为分隔符,将 s 切分成多个子切片,结果中包含sep 本身。如果 sep为空,则将 s 切分成 Unicode 字符列表。如果 s 中没有 sep 子串,则将整个 s 作为 []string 的第一个元素返回。
29
切割
SplitAfterN(s, sep string, n int) []string
以 str 为分隔符,将 s 切分成多个子串,结果中包含sep 本身。如果 sep 为空,则将 s 切分成 Unicode 字符列表。如果 s 中没有 sep 子串,则将整个 s 作为 []string 的第一个元素返回。参数 n 表示最多切分出几个子串,超出的部分将不再切分。如果 n 为 0,则返回 nil;如果 n 小于 0,则不限制切分个数,全部切分。
30
切割
Fields(s string) []string
以连续的空白字符为分隔符,将 s 切分成多个子串,结果中不包含空白字符本身。空白字符有:\t, \n, \v, \f, \r, ’ ‘, U+0085 (NEL), U+00A0 (NBSP) 。如果 s 中只包含空白字符,则返回一个空列表。
31
切割
FieldsFunc(s string, f func(rune) bool) []string
以一个或多个满足 f(rune) 的字符为分隔符,将 s 切分成多个子串,结果中不包含分隔符本身。如果 s 中没有满足 f(rune) 的字符,则返回一个空列表。
32
连接
Join(a []string, sep string) string
将 a 中的子串连接成一个单独的字符串,子串之间用 sep 分隔。
33
转换
ToUpper(s string) string
将 s 中的所有字符修改为其大写格式。对于非 ASCII 字符,它的大写格式需要查表转换。
34
转换
ToLower(s string) string
将 s 中的所有字符修改为其小写格式。对于非 ASCII 字符,它的小写格式需要查表转换。
35
转换
ToTitle(s string) string
将 s 中的所有字符修改为其 Title 格式,大部分字符的 Title 格式就是 Upper 格式,只有少数字符的 Title 格式是特殊字符。这里的 ToTitle 主要给 Title 函数调用。
package main
import (
"fmt"
"strconv"
)
func main() {
// string 转为 int
i, _ := strconv.Atoi("123")
fmt.Println(i)
// int 转为 string,默认十进制便捷版
s1 := strconv.Itoa(123)
fmt.Println(s1)
// int 转为 string,完整版,2-36进制均可
s2 := strconv.FormatInt(int64(123), 10) // 强制转化为int64后使用FormatInt
fmt.Println(s2)
}
3.6.3.3 string 与 float 互转
3.7 类型转换
类型转换格式
数据类型(变量)
数据类型(表达式)
在类型转换时建议低类型转成高类型 保证数据精度
建议整型转成浮点型
高类型转成低类型,可能会丢失精度,或者数据溢出,符号发生变化
将浮点型转成整型,保留数据整数部分,丢弃小数部分
package main
import "fmt"
func main01() {
a, b, c := 10, 20, 40
sum := a + b + c
// 这里对sum使用类型转换,使其结果也为浮点数,这里的数字3是字面变量,会自动转换成浮点数
fmt.Println("平均值是:", float64(sum)/3)
}
func main() {
var a float32 = 1.99
// 将浮点型转成整型,保留数据整数部分,丢弃小数部分
b := int(a)
fmt.Println(b) // 1
}
四、常量
4.1 const 常量定义与使用
常量不允许左值赋值(常量不允许放在等号左边接收右边的值)
常量的定义,一般定义常量使用大写字母
go语言常量的地址,不允许访问
由于常量的赋值是一个编译期行为,所以右值不能出现任何需要运行期才能得出结果的表达式
package main
func main() {
// 常量的定义,一般定义常量使用大写字母
const MAX int = 10
//go语言常量的地址,不允许访问
// fmt.Println(&MAX) // err
}
4.2 字面常量
所谓字面常量(literal),是指程序中硬编码的常量,如:
// 这里面 1 和 5 都是字面常量
fmt.Println(1+5)
4.3 iota 枚举
package main
import "fmt"
func main01() {
// iota枚举格式如果写在一行中值相等,如果换行值在上一行加1
const (
a = iota
b, c = iota, iota
)
fmt.Println(a) // 0
fmt.Println(b) // 1
fmt.Println(c) // 1
}
func main02() {
// 只需要对第一个进行iota赋值,后面会依次增长
const (
a = iota
b
c
d
)
fmt.Println(a) // 0
fmt.Println(b) // 1
fmt.Println(c) // 2
fmt.Println(d) // 3
}
func main() {
// 在定义iota枚举时可以自定义赋值
const (
a = iota
b = 10
c = 20
d
e
f = iota
g
)
fmt.Println(a) // 0
fmt.Println(b) // 10
fmt.Println(c) // 20
fmt.Println(d) // 20
fmt.Println(e) // 20
fmt.Println(f) // 5
fmt.Println(g) // 6
}
package main
import "fmt"
func main() {
var age int
fmt.Print("请输入你的年龄:")
fmt.Scan(&age)
// if 支持一个初始化语句,初始化语句和判断语句用分号分开
if age >= 18 {
fmt.Println("恭喜你成年了哦!")
} else {
fmt.Println("你还是未成年哦!")
}
}
package main
import "fmt"
func main() {
var age, money int
fmt.Print("请输入你的年龄和零花钱:")
fmt.Scan(&age, &money)
// 只有同时满足两个条件才可以上网
if age >= 18 {
fmt.Println("恭喜你成年了哦!")
if money >= 5 {
fmt.Println("大于5元可以上网了哦!")
} else {
fmt.Println("不足5元不可以上网哦!")
}
} else {
fmt.Println("你还是未成年哦!")
}
}
6.1.4 if…else if 结构
语法格式
if 条件判断 {
代码体1
} else if 条件判断1 {
代码体2
} else if 条件判断2 {
代码体3
} else if 条件判断n {
...
} else {
以上都不满足
}
6.1.5 switch 结构
package main
import "fmt"
// 根据输入的年份月份,计算这个月有多少天
func main() {
var y, m int
fmt.Print("请输入年和月:")
fmt.Scan(&y, &m)
switch m {
// 同样的结果可以写一起
case 1, 3, 5, 7, 8, 10, 12:
fmt.Printf("%d年%02d月是:31天", y, m)
case 4, 6, 9, 11:
fmt.Printf("%d年%02d月是:30天", y, m)
case 2:
// 判断是否是闰年:能被4整除,但不能被100整除;能被4整除,也能被400整除。
if y%4 == 0 && y%100 != 0 || y%400 == 0 {
fmt.Printf("%d年%02d月是:29天", y, m)
}else {
fmt.Printf("%d年%02d月是:28天", y, m)
}
default:
fmt.Println("月份输入错误!")
}
}
6.1.6 if…else if 与 switch 的比较
各自优点
if…else if 可以进行区间判断,嵌套使用
switch 执行效率高,可以将多个满足相同条件的值放在一起
各自缺点
if…else if 执行效率低
switch 不建议嵌套使用
6.2 循环结构
// 循环5次
for i := 0; i < 5; i++ {
// 代码体,i可在此调用
}
// 遍历一个数组 i -> index 下标 v -> value 值
for i, v := range array {
// 代码体,i是下标,v是值
}
6.2.1 简单的求和
package main
import "fmt"
func main() {
// 计算1-100的和
sum1 := 0
for i := 1; i <= 100; i++ {
sum1 += i
}
fmt.Println(sum1)
// 计算1-100偶数的和,在for语句中嵌套if条件判断
sum2 := 0
for i := 1; i <= 100; i++ {
if i%2 == 0 {
sum2 += i
}
}
fmt.Println(sum2)
// 计算1-100偶数的和,减少循环次数提高效率
sum3 := 0
for i := 0; i <= 100; i += 2 {
sum3 += i
}
fmt.Println(sum3)
}
6.2.2 喝酒敲七游戏
package main
import "fmt"
func main() {
// 喝酒敲七游戏,何时敲:7的倍数,十位为7,个位为7,求100内哪些数字敲桌子
for i := 1; i < 100; i++ {
if i%7 == 0 || i/10 == 7 || i%10 == 7 {
fmt.Println("敲桌子!")
}else {
fmt.Println(i)
}
}
}
6.2.3 水仙花数
func main() {
// 水仙花数,一个三位数,各个位数的立方和等于这个数本身
for i := 100; i <= 999; i++ {
// 抽出百位
a := i / 100
// 抽出十位
b := i / 10 % 10 // b:= i % 100 / 10
// 抽出个位
c := i % 10
if a*a*a+b*b*b+c*c*c == i {
fmt.Println(i)
}
}
}
6.2.4 九九乘法表
func main() {
// 九九乘法表
// i 控制有几行
for i := 1; i <= 9; i++ {
// j 控制每行有几个
for j := 1; j <= i; j++ {
fmt.Printf("%d * %d = %d\t", i, j, i*j)
}
fmt.Println()
}
}
6.2.5 打印等腰三角形 ▲
func main() {
// 打印等腰三角形
line := 5
// i 控制有几行
for i := 0; i < line; i++ {
// j 控制每行有几个左空格,行数越大空格越少,所以减 i
for j := 0; j < line-i-1; j++ {
fmt.Print(" ")
}
// k 控制每行有几个星星,i*2+1可以得到1 3 5 7 9
for k := 0; k < i*2+1; k++ {
fmt.Print("*")
}
// l 控制右边的空格,规则同 j ,其实可以不写
for l := 0; l < line-i-1; l++ {
fmt.Print(" ")
}
fmt.Println()
}
}
// break
func main0901() {
i := 0
// 没有参数的for是死循环
for {
// 有些程序循环中,不知道程序执行次数,只有条件满足时程序停止
if i == 5 {
// 跳出语句跳出当前循环
break
}
i++
}
}
// continue
func main0902() {
for i := 0; i <= 5; i++ {
if i == 3 {
// 结束本次循环,继续下次循环
// 如果在程序中入到continue后剩余代码不会执行,会回到循环的位置
continue
}
fmt.Println(i)
}
}
// goto 尽量少用
func main() {
fmt.Println(1)
// 如果在代码中入到goto,会跳到所定义的标志位
// 可以在一个循环中跳到另外一个循环中,可以在一个函数中跳到另外一个函数中
goto FLAG1
fmt.Println(2)
fmt.Println(3)
fmt.Println(4)
fmt.Println(5)
FLAG1:
fmt.Println("标志位下方不能也是标注位,所以打了这句话输出!")
//死循环
FLAG2:
fmt.Println(6)
goto FLAG2
fmt.Println(7)
}
七、函数
7.1 函数定义
函数只能定义一次, 在整个项目中函数名是唯一的,不能重名
在函数调用时参数为实际参数(实参)有具体的值 用来给形式参数(形参)传递数据
func 函数名(参数列表)(返回值列表){
代码体
}
7.2 不定参函数
...不定参,在函数调用时可以传递不定量(0-n)的参数
不定参使用数据格式为切片
package main
import "fmt"
func main() {
fmt.Println(sum1(1, 2, 3))
fmt.Println(sum2(1, 2, 3))
}
// 一个求和的函数
func sum1(array ...int) int {
// 下标是从0开始的,为了减少循环次数,设置默认值是下标0
sum := array[0]
// 通过array[下标]可以找到具体数据的值
for i := 1; i < len(array); i++ {
sum += array[i]
}
return sum
}
func sum2(array ...int) int {
sum := 0
// 通过for循环遍历集合中的数据
//i -> index 下标 v -> value 值,如果数据的值不需要接收,可以通过匿名变量 _ 来接收数据
for _, v := range array {
sum += v
}
return sum
}
package main
import "fmt"
// 最常规的返回值,只有一个 int
func test1(a, b int) int {
return a + b
}
// 推荐使用,提前定义好返回值变量,注意此变量只能在函数内部使用
func test2(a, b int) (sum int) {
sum = a + b
return
}
// 推荐使用,多返回值
func test3(a, b int) (sum, sub int) {
sum = a + b
sub = a - b
return
}
func main() {
fmt.Println(test1(10, 20))
fmt.Println(test2(10, 20))
fmt.Println(test3(10, 20))
}
7.5 函数类型
函数也有它的类型,称之为函数类型
同样函数类型也可以使用 type 关键字为其取别名
package main
import "fmt"
// 此函数类型是 func(int, int)
func demo1(a, b int) {
fmt.Println(a + b)
}
// 此函数类型是 func(int, int) int
func demo2(a, b int) int {
return a + b
}
// 此函数类型是 func(int, int) (int, int)
func demo3(a, b int) (sum, sub int) {
sum = a + b
sub = a - b
return
}
func main() {
// 打印函数类型
fmt.Printf("%T\n", demo1) // func(int, int)
fmt.Printf("%T\n", demo2) // func(int, int) int
fmt.Printf("%T\n", demo3) // func(int, int) (int, int)
// 函数的名字表示一个地址,函数的地址在代码区
fmt.Println(demo1) // 0x492d10
// 可以用一个变量来表示函数,此变量的类型,就是函数类型 func(int, int)
f := demo2
fmt.Println(f(10,20)) // 30
// 定义函数类型,为已存在的数据类型起别名,func(int, int) int 类型,系统早已内置
type FUNCDEMO func(int, int) int
// 定义 f2 变量,使用类型别名
var f2 FUNCDEMO
f2 = demo2
fmt.Printf("%T\n", f2) // main.FUNCDEMO
}
7.6 函数的作用域
首字母大写的函数为公有函数,可在包之外被调用
首字母小写的函数为私有函数,仅可在包之内调用
7.6.1 局部变量
定义在函数内部的为局部变量,只能在函数内部使用
为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用
7.6.2 全局变量
定义在函数外部的变量,称为全局变量,作用域在整个包之内使用
除非首字母大写,不然只能在当前包内使用
全局变量名可以和局部变量名重名
go语言中会采用就进原则,如果函数内部定义局部变量和全局变量名重名,会优先使用局部变量
全局变量储存在内存的数据区
如果全局变量定义时有值,存储在初始化数据区 没有值存储在未初始化数据区
7.7 匿名函数
匿名函数的主要作用就是实现了闭包
匿名函数一般定义在函数之内
// 匿名函数在 func 后面不加函数名,尾巴多出来的小括号表示调用此函数
func(){
函数体
}()
// 如果想让匿名函数也拥有函数名,如下
f := func(){
函数体
}
// 调用函数
f()
// 注意如果尾巴加了小括号即代表调用
f := func(a, b int) int {
函数体
}(a, b)
// 此时的 f 不代表函数名,代表的是返回值
var s int = f
7.8 递归函数
自己调用自己的函数,就是递归函数
注意死递归比死循环更严重
package main
import "fmt"
// 计算阶乘 n! = 1 * 2 * 3 * ... * n
// 带返回值的递归函数,比较复杂但(推荐使用)
func factorial(n int) (product int) {
if n == 1 {
// 1的阶乘等于1,所以要返回1,不然product默认为0
return 1
}
// 阶乘要一直乘,所以这里再乘与自己本身里的乘积,传进去的参数要减1
return n * factorial(n - 1)
}
// 不带返回值的递归函数,需要借用外部全局变量
var s int = 1
func factorialDemo(n int) {
if n == 1 {
return
}
s *= n //5*4*3*2
factorialDemo(n - 1)
}
func main() {
// 调用第一种
fmt.Println(factorial(10))
// 调用第二种
factorialDemo(10)
fmt.Println(s)
}
八、数据格式
8.1 数组
8.1.1 数组的定义
数组是一系列相同数据类型在内存中有序存储的数据集合
// 伪代码
var 数组名 [元素个数]数据类型
// 定义了10个整型变量的数组
var arr [10]int
// 如果不赋值,直接输出,结果默认全部是 0
var a [10]int
// 如果不赋值,直接输出,结果默认全部是 0
var a [10]float64
// 如果不赋值,直接输出,结果默认全部是 空字符
var a[10]string
// 如果不赋值,直接输出,结果默认全部是 false
var a [10]bool
通过for循环完成数组的赋值与输出
package main
import "fmt"
func main() {
// 对有规律的数据普通赋值方法
var a [5]int
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
// 对有规律的数据for循环赋值,推荐使用
var b [5]int
for i := 0; i < len(b); i++ {
b[i] = i + 1
}
// 验证赋值结果
for i, v := range b {
fmt.Printf("下标:%d,元素值:%d\n", i, v)
}
}
package main
import "fmt"
func main() {
var arr = [5]int{1, 5, 9, 3, 2}
max := arr[0]
for i := 1; i < len(arr); i++ {
if arr[i] > max {
max = arr[i]
}
}
fmt.Println(max)
}
8.1.6.2 数组逆置(反转)
package main
import "fmt"
func main() {
var arr [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 预定义最小下标和最大下标
min := 0
max := len(arr) - 1
for min < max {
if min >= max {
break
}
arr[min], arr[max] = arr[max], arr[min]
min++
// 重点:最大下标要 --
max--
}
fmt.Println(arr)
}
8.1.6.3 冒泡排序
package main
import "fmt"
func main() {
var arr [10]int = [10]int{9, 1, 5, 6, 8, 2, 10, 7, 4, 3}
// 外层执行一次内层执行一周,外层控制行
// 这里 len-1 是因为,10个数只要比较9次即可
for i := 0; i < len(arr)-1; i++ {
// 这里len-i 是因为每行确定一个最大数,那么已确定的就不必再比较,再-1 是因为最后一行不需要再比较
for j := 0; j < len(arr)-i-1; j++ {
// 如何前面大于后面,(大于号是升序,小于号是降序)
if arr[j] > arr[j+1] {
// 交换数据
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
fmt.Println(arr)
}
8.1.6.4 随机数
先创建随机数种子
如果没有创建随机数种子称为伪随机数
伪随机数使用的是 1970-01-01 00:00:00 的时间戳
再创建随机数
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 创建随机数种子,这里使用纳秒级别的时间戳
rand.Seed(time.Now().UnixNano())
for i := 0; i < 10; i++ {
// 随机生成10个 1~10 的随机数,所以+1
fmt.Println(rand.Intn(10) + 1)
}
}
8.1.6.5 数组去重
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 随机双色球彩票
// 红色 1-33,选择6个,不能重复;蓝球 1-16,选择1个,可以和红球重复
// 创建随机数种子,使用纳秒基本的时间戳
rand.Seed(time.Now().UnixNano())
// 预定义一个存放红球的数组
var red [6]int
// 第一层循环给数组填满6个随机数
for i := 0; i < 6; i++ {
red[i] = rand.Intn(33) + 1
// 第二层循环对比,所填的随机数不能重复
for j := 0; j < i; j++ {
if red[i] == red[j] {
red[i] = rand.Intn(33) + 1
// 重点的坑,再次随机生成的数还是要检查是否重复,因此重置计数器,循环执行到上面是进行++操作后值为0
j = -1
}
}
}
fmt.Println("红球:", red, "蓝球:", rand.Intn(16)+1)
}
8.1.7 二维数组
8.1.7.1 二维数组的定义
// 一维数组
var arr [10]int
// 定义一个拥有2行3列的二维数组
var arr [2][3]int