Go 语言入门笔记

63

输入输出

输入,需要 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")
	}()
}