数组
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
声明一维数组
语法:
var variable_name [SIZE] variable_type
实例:
var balance [10] float32
初始化一维数组
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或者
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
一维数组遍历
a1 := [...]int{1, 3, 5, 7, 8}
for index, value := range a1 {
other := 9 - value
for index2 := index + 1; index2 < len(a1); index2++ {
if a1[index2] == other {
// 另一半在数组中,把它们的索引打印出来
fmt.Printf("它们的索引是:(%d %d)\n", index, index2)
}
}
}
完整实例:
package main
import "fmt"
// 1. 定义一个数组[1,3,5,7,8],求数组中所有元素的和
func main() {
a1 := [...]int{1, 3, 5, 7, 8}
fmt.Println(a1)
// // 1. 数组求和
// sum := 0
// // := 相当于声明变量并且赋值
// for _, v := range a1 {
// // fmt.Println(v)
// sum = sum + v
// }
// fmt.Println(sum)
// 2. 找出数组中和为指定值的两个元素的下标,比如从数组[1,3,5,7,8]中找出和为8的两个元素的下标分别为(0,3)和(1,2)。
// 遍历数组,
// 2.1依次取出每个元素
// 2.2 计算一下 other= 8-当前值
// 2.3 在不在数组中,在的话把索引拿出来
// [1, 3, 5, 7, 8]
for index, value := range a1 {
other := 9 - value
for index2 := index + 1; index2 < len(a1); index2++ {
if a1[index2] == other {
// 另一半在数组中,把它们的索引打印出来
fmt.Printf("它们的索引是:(%d %d)\n", index, index2)
}
}
}
}
多维数组
语法:
var 数组名 [大小][大小]类型
比如:
var b [3][2]int
b = [3][2]int{
[2]int{1, 2},
[2]int{3, 4},
}
声明同时赋值:
var c = [3][2]int{
{1, 2},
{3, 4},
{5, 6},
}
多维数组遍历:
for i := 0; i < len(d); i++ {
for j := 0; j < len(d[i]); j++ {
fmt.Printf("%d-%d\n", i, d[i][j])
}
}
切片
切片和数组相似,它们都是保存相同数组类型元素的容器,但是切片的元素个数是可变的, 数组不可变
切片不需要明确指定元素的个数
切片创建
1.方式一:
var s []int //创建int类型切片
var s []string //创建string类型切片
2.通过 make() 函数创建切片:
slice := make([]int, 5)
内部实现:
切片是一个很小的对象,它对底层的数组(内部是通过数组保存数据的)进行了抽象,并提供相关的操作方法;
切片是有三个字段的数据结构,这些数据结构包含Go语言需要操作底层数组的元数据
使用append可以往切片里添加元素:
var a = []int{} //空切片
a = append(a, 1)
Map
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
声明类型
声明map类型
var m1 map[string]int //未初始化就是 nil
使用make初始化map
m1 = make(map[string]int, 100)
m1["nazha"] = 90
m1["haojie"] = 100
声明map类型时直接初始化
m2 := map[string]string{
"haojie": "hehe",
"yawei": "heihei",
}
map的键值对操作
遍历键值对
for k, v := range m2 {
fmt.Println(k, v)
}
遍历键
for k := range m2 {
fmt.Println(k)
}
判断map中是否存在某个键值对
v, ok := m2["haojie"]
// ok返回的是布尔值,能取到就返回true,取不到就返回false
if !ok {
fmt.Println("查无此人")
} else {
fmt.Println(v)
}
删除键值对
delete(m2, "haojie")
Map和切片操作
切片的元素是map
初始化切片
mapSlice := make([]map[string]int, 3, 10)
添加元素
mapSlice = append(mapSlice, map[string]int{"aaa": 10})
mapSlice = append(mapSlice, map[string]int{"bbb": 100})
map中元素的值是切片
对外层的map做初始化
sliceMap := make(map[string][]int, 10)
对map的值(切片)做初始化
sliceMap["haojie"] = make([]int, 3, 10)
sliceMap["haojie"][0] = 1
sliceMap["haojie"][1] = 2
sliceMap["haojie"][2] = 3
函数
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
- func:函数由 func 开始声明
- function_name:函数名称,函数名和参数列表一起构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
- 函数体:函数定义的代码集合。
没有参数没有返回值的函数
func sayHello() {
fmt.Println("Hello 沙河!")
}
带参数的函数
func sayHi(name string) {
fmt.Printf("Hello %s\n", name)
}
带参数和返回值
func add(a int, b int) int {
ret := a + b
return ret
}
func add3(a, b int) (ret int) {
ret = a + b
return
}
可变参数
func add4(a int, b ...int) int {
ret := a
fmt.Println(a)
fmt.Printf("b=%v type:%T\n", b, b)
for _, v := range b {
ret = ret + v
}
return ret
}
func add5() (int, int, int) {
return 1, 2, 3
}
函数可以作为变量、参数、返回值
package main
import "fmt"
// 函数可以作为变量、参数、返回值
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
// calc是一个函数,它接收三个参数,返回一个int类型的返回值
// 其中,参数a和b是int类型
// 参数f 是一个函数类型,这个函数接收两个int类型的参数,返回一个int类型的返回值
func calc(a, b int, f func(int, int) int) int {
return f(a, b)
}
func main() {
f1 := add
fmt.Printf("f1:%T\n", f1)
fmt.Println(f1(10, 20))
//把add当成一个参数传进calc中
ret := calc(100, 200, add)
fmt.Println(ret)
// 把sub当成一个参数传进calc中
ret = calc(100, 200, sub)
fmt.Println(ret)
}
匿名函数
匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:
func(a,b int,z float64) bool{
return a*b
}
package main
import "fmt"
// 匿名函数
func main() {
func() {
fmt.Println("Hello world!")
}() // 花括号后加()表示函数调用
}
闭包函数
闭包函数,即在一个封闭作用域中的函数,这个函数可以使用封闭作用域中的所有变量。也就是使用该函数时除了函数中的变量(函数变量)还可以对闭包中的函数(自由变量进行操作)
示例一:
// 定义一个函数f1
// f1不接受参数
// f1返回一个函数类型,这个函数不接收参数也没有返回值
func f1(num int) func(int) int {
f := func(x int) int {
fmt.Println("找到外层函数的变量num", num)
return num + x
}
return f
}
示例二:
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
示例三:
func calc(base int) (func(int) int, func(int) int) {
add := func(i int) int {
base += i // 引用了外层的base变量同时还修改了base
return base
}
sub := func(i int) int {
base -= i
return base
}
return add, sub
}
延迟语句defer
Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
package main
import "fmt"
func testDefer() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("函数马上要结束了...")
}
func main() {
testDefer()
}
案例:
打印200~1000之间的质数(素数)
package main
import "fmt"
func main() {
for i := 200; i < 1000; i++ {
// fmt.Println(i)
flag := true
//判断i是否为质数,如果是就打印,如果不是就不打印
for j := 2; j < i; j++ {
if i%j == 0 {
//不是质数
flag = false
break
}
}
//整个第二层的for循环结束了还没有break说明是质数
if flag {
fmt.Printf("%d是质数.", i)
}
}
}
打印9*9乘法表
package main
import "fmt"
func main() {
for i := 1; i < 10; i++ {
for j := i; j < 10; j++ {
fmt.Printf("%d*%d=%d\t", j, i, i*j)
}
fmt.Println()
}
}