Go 语言入门笔记
输入输出
输入,需要 fmt
包下的几个方法,比如 Scanln
package main
import (
"fmt"
)
func main() {
var a int
fmt.Print("请输入一个整数:")
fmt.Scanln(&a) // 将输入的值赋值给变量 a 的内存地址
fmt.Printf("a 的值为:%d\n", a)
}
或者可以使用 scanf
的方式格式化输入
package main
import (
"fmt"
)
func main() {
var a int
var b string
fmt.Print("请输入一个整数和一个字符串:")
fmt.Scanf("%d,%s", &a, &b) // 格式化输入
fmt.Printf("a 的类型为:%T,值为:%d\n", a, a)
fmt.Printf("b 的类型为:%T,值为:%s\n", b, b)
}
// 控制台输出
/*
请输入一个整数和一个字符串:100,aaa
a 的类型为:int,值为:100
b 的类型为:string,值为:aaa
*/
还可以使用 bufio
这个包
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Print("请输入一个整数:")
reader := bufio.NewReader(os.Stdin)
s, _ := reader.ReadString('\n')
fmt.Println(s)
}
输出的话就 fmt 包中的三个方法
fmt.Print()
fmt.Println()
fmt.Printf()
流程控制
go语言中 for 循环的特性比较有意思的是给 for 命名,然后 break 越级跳出循环,比如
package main
import (
"fmt"
)
func main() {
out: // 给 for 循环命名为 out
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d x %d = %d\t", j, i, i*j)
if j >= 5 {
break out // 本来只是结束当前循环,加上名字,就可以跳出上级循环
}
}
fmt.Println()
}
}
生成随机数
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 使用当前时间的纳秒部分作为种子
seed := time.Now().UnixNano()
randSource := rand.NewSource(seed)
randomGenerator := rand.New(randSource)
// 生成随机整数
randomNumber := randomGenerator.Intn(100) // 生成0到99之间的随机整数
fmt.Println("随机整数:", randomNumber)
}
数组
几种定义数组的方式
package main
import (
"fmt"
)
func main() {
// 常规写法
var arr [5]int
arr[0] = 12
arr[1] = 22
fmt.Println(arr)
// 数组的其它写法
var arr2 = [4]int{1, 2, 3, 4}
fmt.Println(arr2)
// 在指定位置存储数据
var arr3 = [5]string{1: "hello", 3: "go"}
fmt.Println(arr3)
// 自动推断
arr4 := [...]int{1, 2, 3, 4, 5, 6}
fmt.Println(arr4)
}
遍历数组的几种方式
package main
import (
"fmt"
)
func main() {
arr := [...]int{1, 2, 3, 4, 5, 6}
// 访问数组中的元素,可以使用 for 循环
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
// 也可以用 range
for index, value := range arr {
fmt.Printf("数组下标为%d的值是%d\n", index, value)
}
}
每一个数组都有自己的类型,类型为 [size]type
切片
切片是引用类型,相当于动态数组,创建方式如下
package main
import "fmt"
func main() {
// 一般创建方式
var s1 = []int{1, 2, 3, 4}
fmt.Println(s1)
// 使用 make 方法创建
s2 := make([]int, 3, 10) // 表示创建了一个容量为10的切片,初始值为[0 0 0]
fmt.Println(s2)
}
在切片中追加数据,需要用到 append ,如果没有超过切片的容量,直接添加,如果超过容量,切片会扩容(成倍增加)
s2 = append(s2, 1, 2, 3)
在数组中创建切片,由于切片是引用类型,如果更改了切边中的值,对应的数组也会被改变
package main
import "fmt"
func main() {
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(a) // [1 2 3 4 5 6 7 8 9 10]
b := a[:5] // 切下标 0-4
fmt.Println(b) // [1 2 3 4 5]
c := a[3:8]
fmt.Println(c) // [4 5 6 7 8]
}
如果对切片进行操作时,扩容了而原数组容量不够,切边会自动开辟一块新的地址,存储扩容后的数据,然后跟之前的数组就没有任何关系了
package main
import "fmt"
func main() {
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(a) // [1 2 3 4 5 6 7 8 9 10]
b := a[:5] // 切下标 0-4
fmt.Println(b) // [1 2 3 4 5]
c := a[3:8]
fmt.Println(c) // [4 5 6 7 8]
fmt.Println("----------------------------")
b = append(b, 1, 1, 1, 1, 1, 1, 1, 1)
fmt.Printf("数组a%T的内存地址:%p,长度:%d,容量:%d\n", a, &a, len(a), cap(a)) // 数组a[10]int的内存地址:0x14000198000,长度:10,容量:10
fmt.Printf("切片b%T的内存地址:%p,长度:%d,容量:%d\n", b, b, len(b), cap(b)) // 切片b[]int的内存地址:0x140001a0000,长度:13,容量:20
}
MAP
创建 map 的几种方式
package main
import "fmt"
func main() {
var map1 map[int]string // 只是进行声明,此时为 nil,不能直接用
var map2 = make(map[int]string) // make 创建,可以用
var map3 = map[string]int{"go": 10, "python": 11} // 可以用
}
strings 包的使用
package main
import (
"fmt"
"strings"
)
func main() {
s := "hello go!"
// s 字符串中是否包含指定内容,返回 bool
fmt.Println(strings.Contains(s, "go")) // go 在字符串 s 中,返回 true
// s 字符串中是否包含指定内容中的任意字符, 返回 bool
fmt.Println(strings.ContainsAny(s, "abcde")) // e 在字符串 s 中,返回 true
// 统计在 s 字符串中,某个字符出现的次数,返回 int
fmt.Println(strings.Count(s, "o")) // 返回 2
// 是否以某个字符串开头?返回 bool
fmt.Println(strings.HasPrefix(s, "hello")) // 返回true
// 字符串的拼接
s2 := []string{"aaa", "bbb", "ccc"} // 创建一个切片
fmt.Println(strings.Join(s2, ",")) // 用 , 进行拼接
// 字符串的切割
s3 := "hello,go,gogogo" // aaa,bbb,ccc
fmt.Println(strings.Split(s3, ",")) // [hello go gogogo]
// 重复拼接自己
fmt.Println(strings.Repeat("*", 20)) // ********************
// 字符串替换
s4 := strings.ReplaceAll(s3, "go", "sex") // hello,sex,sexsexsex
fmt.Println(s4)
// 大小写转换
s5 := "PassW0rd"
fmt.Println(strings.ToLower(s5))
fmt.Println(strings.ToUpper(s5))
}
strconv 包的使用
函数的可变参数
形参必须写类型
func test(a int, b int) int {
sum := 0
sum = a + b
return sum
}
如果参数类型一致,可以简写
func test(a, b int) int {
sum := 0
sum = a + b
return sum
}
如果传入的参数不固定,可以用...表示
func test(a ...int) int {
sum := 0
for _, i := range a {
sum += i
}
return sum
}
defer 的使用
defer 起到延时的作用,按照栈结构先 defer 的后执行,后 defer 的先执行
package main
import "fmt"
func main() {
fmt.Println("1")
defer test("2")
fmt.Println("3")
defer test("4")
}
func test(str string) {
fmt.Println(str)
}
/*
~/go/src/stu $ go run test.go
1
3
4
2
*/
匿名函数
没有名字的函数,一般只调用一次
package main
import "fmt"
func main() {
func() {
fmt.Println("hello")
}()
}