go语言学习笔记。
https://docs.hacknode.org/gopl-zh/ch1/ch1-01.html
PDF蓝奏云下载https://www.lanzous.com/i8n12od
Go语言高级编程
《Effective Go》中英双语版
Go语言将数据类型分为四类:基础类型、复合类型、引用类型和接口类型。基础类型:数字、字符串、和布尔型。复合数据类型:数组、结构体(通过组合简单类型,来表达更加复发的数据结构)。引用类型包括:指针、切片、字典、函数、通道。
package main
import (
"encoding/json"
"fmt"
)
//结构体和json
func main() {
p1 := person{
Name: "go学习",
Age: 1,
}
fmt.Printf("%#v\n", p1)
//1 把go语言中结构体-->json| 序列化
//2 反序列化 |json-->go结构体
marshal, err := json.Marshal(p1)
if err != nil {
fmt.Println("marsh1 failed")
return
}
fmt.Printf("%#v\n", string(marshal))
// 反序列化
var p2 = new(person)
json.Unmarshal([]byte(string(marshal)), p2) //传入指针,以便修改结构体的值
fmt.Println(*p2)
}
type person struct {
Name string `json:"name""`
Age int `json:"age"`
}
map增删查改学生管理系统
package main
import (
"fmt"
"os"
)
// 学生管理系统
type student struct {
id int64
name string
}
func NewStudent(id int64, name string) {
}
type stuMgr struct {
//保存所有 学生
allStudent map[int64]student
}
var (
allStudent map[int64]student
)
func (s stuMgr) addStu() {
var (
id int64
nameinput string
)
fmt.Println("输入学生ID")
fmt.Scanln(&id)
fmt.Println("输入学生姓名")
fmt.Scanln(&nameinput)
p := student{id: id, name: nameinput}
s.allStudent[id] = p
}
//查看学生
func (s stuMgr) showAllStudent() {
for _, v := range s.allStudent {
fmt.Println("|学号", v.id, " |姓名", v.name)
}
}
func (s stuMgr) delStudent() {
fmt.Println("输入要删除的ID")
var delId int64
fmt.Scanln(&delId)
delete(s.allStudent, delId)
fmt.Println("-----删除后的结果----")
s.showAllStudent()
}
func (s stuMgr) modify() {
var (
id int64
nameinput string
)
fmt.Println("输入要修改学生ID")
fmt.Scanln(&id)
fmt.Println("输入修改后的学生姓名")
fmt.Scanln(&nameinput)
p := student{id: id, name: nameinput}
s.allStudent[id] = p
}
// 管理者
var smr stuMgr
//查看学生
// 删除 学生
// 新增
func main() {
smr = stuMgr{allStudent: make(map[int64]student, 100)}
for {
//菜单
showMenu()
//等待输入
fmt.Print("输入选项:")
var choice int
fmt.Scanln(&choice)
fmt.Println("输入的是", choice)
switch choice {
case 5:
os.Exit(1)
case 1:
smr.showAllStudent()
case 2:
smr.addStu()
case 3:
smr.modify()
case 4:
smr.delStudent()
default:
fmt.Println("输入有误")
}
}
}
func showMenu() {
fmt.Println("welcole sms!")
fmt.Println(`
1查看所有
2添加
3 修改
4 删除
5 退出
`)
}
import "fmt"
//接口 是一种类型
type cat struct{}
type dog struct{}
type animal interface {
speak()
}
func (c cat) speak() {
fmt.Println("喵喵喵")
}
func (d dog) speak() {
fmt.Println("汪汪汪")
}
func da(a animal) {
fmt.Println("方法执行")
a.speak()
}
func main() {
var (
cat = cat{}
dog = dog{}
)
da(cat)
da(dog)
}
如果是使用值接受者与使用指针接受者实现接口的区别
//类型断言
func main() {
assign(12)
assin2(true)
}
func assin2(a interface{}) {
fmt.Printf("%T\n", a)
switch a.(type) {
case string:
fmt.Println("string is :", a.(string))
case bool:
fmt.Println(" bool ", a)
default:
fmt.Println("default")
}
}
func assign(a interface{}) {
fmt.Printf("%T", a)
s, ok := a.(string)
if ok {
fmt.Println("this is string ", s)
} else {
fmt.Println("其他类型")
}
}
func randDemo() {
rand.Seed(time.Now().Unix())
for i := 1; i < 6; i++ {
r1 := rand.Int()
r2 := rand.Intn(10) //0<=x<10
fmt.Println(r1, r2)
}
}
元祖赋值是另一种形式的赋值语句,它允许同时更新多个变量的值,在赋值之前,赋值语句右边的所有表达式将会先进行求值,然后在统一更新左边对应变量的值。这对于处理有些同时出现在元组赋值语句左右两边的变量很有帮助,例如可以交换两个变量的值
x, y = y, x
a[i], a[j] = a[j], a[i]
计算两个整数的最大公约数(GCD)
func gcd(x, y int) int {
for y != 0 {
x, y = y, x%y
}
return x
}
计算斐波那契数列(Fibonacci)的第N个数:
func fib(n int) int {
x, y := 0, 1
for i := 0; i < n; i++ {
x, y = y, x+y
}
return x
}
元组赋值也可以使一系列琐碎赋值更加紧凑。
i, j, k = 2, 3, 5
当调用一个函数时,会对其每一个参数值值进行拷贝,如果一个函数需要更新一个变量,或者函数的其中一个参数实在太大我们希望能够避免这种默认的拷贝,这种情况我们就需要用到了指针。对应到我们这里用来更新接收器的对象方法,当这个接受者变量本身比较大时。我们就可以用其指针而不是对象来声明方法。
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
这个方法的名字是(*Point).ScaleBy
。这里的括号必须的;没有括号的话这个表达式可能会被理解为*(Point.ScaleBy)
在现实的程序里,一般会约定如果Point这个类有一个指针作为接收器的方法,那么所有的Point的方法都必须有一个指针接收器,即使是那些并不需要这个指针接收器的函数。
要想调用指针型方法(*Point).ScaleBy
,只要提供一个Point类型的指针即可,如下
r := &Point{1, 2}
r.ScaleBy(2)
fmt.Println(*r) // "{2, 4}"
或者
p := Point{1, 2}
pptr := &p
pptr.ScaleBy(2)
fmt.Println(p) // "{2, 4}"
或者
p := Point{1, 2}
(&p).ScaleBy(2)
fmt.Println(p) // "{2, 4}"
相比第一种,后两种方法比较笨拙,幸运的是,go语言本身会帮我们,如果接收器p是一个Point类型的变量,并且其方法需要一个Point指针作为接收器,可以用下面这种简短的写法:
p.ScaleBy(2)
编译器会隐式地帮我们用&p去调用ScaleBy这个方法。这种简写方法只适用于变量,包括struct里的字段以及array和slice内的元素。
func downPic() {
client := &http.Client{}
url := "https://i5.mmzztt.com/2019/06/20a03.jpg"
request, err := http.NewRequest("GET", url, nil)
request.Header.Add("referer", "https://www.mzitu.com/190776")
request.Header.Add("accept", "image/webp,image/apng,image/*,*/*;q=0.8")
if err != nil {
fmt.Println("请求失败")
panic(err)
}
//处理请求结果
response, err := client.Do(request)
defer response.Body.Close()
all, err := ioutil.ReadAll(response.Body)
ioutil.WriteFile("d:/"+path.Base(url), all, 0644)
}
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery" //类似于 jquery
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
var finished = make(chan struct{})
// goquery 学习使用 下载图片
func main() {
//
strUrl := "https://www.mzitu.com/179574"
res, err := http.Get(strUrl)
if err != nil {
log.Println(err)
return
}
defer res.Body.Close()
//解析获取的 内容 为Dom
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
picUrl, exists := doc.Find(".main-image").Find("img").Attr("src")
//fmt.Println("图片路径-------", picUrl, exists)//https://i5.mmzztt.com/2019/06/20a01.jpg
if !exists { //返回true表示获取到属性
log.Fatalln("获取图片路径出现错误", picUrl)
return
}
//从 下一页 上一页位置获取 总页码
find := doc.Find(".pagenavi").Find("span")
node := goquery.NewDocumentFromNode(find.Get(find.Size() - 2))
picCountNumInt, err := strconv.Atoi(node.Text())
if err != nil {
log.Println("总页数 字符串转换 数字出错")
return
}
//url前缀 和文件名
picUrlPrefix, fileName := filepath.Split(picUrl)
log.Println(picUrlPrefix, "| 总页数", picCountNumInt)
for i := 1; i <= picCountNumInt; i++ {
newFileName := strings.Replace(fileName, "01", fmt.Sprintf("%02d", i), 1)
downPic(picUrlPrefix+newFileName, picUrl)
}
fmt.Println(picCountNumInt)
}
//下载图片
func downPic(name string, refererurl string) {
//|创建存储路径
savePath := "d:/pic/ps/179574"
os.MkdirAll(savePath, 0666)
client := &http.Client{}
request, err := http.NewRequest("GET", name, nil)
request.Header.Add("referer", refererurl) //需要设置 referer 才能访问到
request.Header.Add("accept", "image/webp,image/apng,image/*,*/*;q=0.8")
if err != nil {
fmt.Println("请求失败")
panic(err)
}
//处理请求结果
response, err := client.Do(request)
defer response.Body.Close()
all, err := ioutil.ReadAll(response.Body)
ioutil.WriteFile(savePath+"/"+path.Base(name), all, 0644)
log.Println(name)
}
//输出2位整数,不够2位补0
func intToStr() {
n := 32
sInt := fmt.Sprintf("%02d", n)
log.Println(sInt, "===========")
}
package main
import (
"fmt"
"log"
"regexp"
)
const text = `my email is [email protected]
[email protected]
[email protected]
em2 is [email protected]
`
func main() {
/********************************************
.|表示匹配任意字符
+表示匹配一个或多个
* 表示匹配零个或多个
*********************************************/
//compile := regexp.MustCompile(`([a-zA-Z0-9]+)@[a-zA-Z0-9]+\.[a-zA-Z0-9]+`) //\在其他中需要用双斜杆
//compile := regexp.MustCompile(`[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9.]+`) //与上面哪行相比是为了匹配出 [email protected](因为其中包含2个点)
//3 使用正则表达式的提取功能
compile := regexp.MustCompile(`([a-zA-Z0-9]+)@([a-zA-Z0-9]+)\.([a-zA-Z0-9.]+)`) //与上面哪行相比是为了匹配出 [email protected](因为其中包含2个点)
findString := compile.FindString(text)
log.Println(findString)
// 查找所有的
allString := compile.FindAllString(text, -1)
log.Println(allString)
log.Println(`3 使用正则表达式的提取功能|`)
//3 使用正则表达式的提取功能|
submatch := compile.FindAllStringSubmatch(text, -1) // 返回的是 [][]string
for _, m := range submatch {
for _, ma := range m {
fmt.Printf("%s ", ma) //[email protected] qqs qq com
}
fmt.Println()
}
}
Go语言内置的flag包实现了命令行参数的解析
flag.Type()
基本格式如下:
flag.Type(flag名, 默认值, 帮助信息)*Type
例如我们要定义姓名、年龄、婚否三个命令行参数,我们可以按如下方式定义:
package main
import (
"flag"
"log"
)
func main() {
log.Println("flag 示例")
name := flag.String("name", "张三", "姓名")
age := flag.Int("age", 18, "年龄")
married := flag.Bool("married", false, "婚否")
flag.Parse()
log.Println(name,age,married)//表示地址
log.Println(*name,*age,*married)
}
flag.TypeVar()
基本格式如下: flag.TypeVar(Type指针, flag名, 默认值, 帮助信息) 例如我们要定义姓名、年龄、婚否三个命令行参数,我们可以按如下方式定义:
var name string
var age int
var married bool
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.Parse()
上述定义好参数后,需要调用flag.Parse()来对命令行参数进行解析。
支持的命令行参数格式有以下几种:
-flag xxx|使用空格,一个-符号
--flag xxx|使用空格,两个-符号
-flag=xxx|使用等号,一个-符号
--flag xxx|使用等号,2个-符号
package main
import (
"fmt"
"os"
)
/********************************************
--------------------
广度优先搜索 走迷宫
*********************************************/
func main() {
//step 1 从文件加载地图
maze := readMaze("Maze/maze.txt")
showMap(maze)
//左上角 和 右下角 作为 起点和终点 |
steps := walk(maze, point{0, 0}, point{len(maze) - 1, len(maze[0]) - 1})
num := stepNum(steps, point{len(maze) - 1, len(maze[0]) - 1})
fmt.Printf("arrival terminal point: %d", num)
fmt.Println("\n走过的路线是")
showMap(steps)
}
type point struct {
i, j int
}
// 方向 i是行,j是列|上左 下右
var dirs = [4]point{
{-1, 0}, {0, -1}, {1, 0}, {0, 1},
}
//
func (p point) add(r point) point {
return point{p.i + r.i, p.j + r.j}
}
//价差某个点是否越界,并返回该点的值
func (p point) at(grid [][]int) (int, bool) {
// 检查行是否越界
if p.i < 0 || p.i >= len(grid) {
return 0, false
}
//检查列是否越界
if p.j < 0 || p.j >= len(grid[p.i]) {
return 0, false
}
return grid[p.i][p.j], true
}
// 走迷宫|广度优先搜索
func walk(maze [][]int, start, end point) [][]int {
steps := make([][]int, len(maze))
for i := range steps {
steps[i] = make([]int, len(maze[i]))
}
//作为队列使用,存放走得通的点,当某个点要被搜索便把他出队列
Q := []point{start}
for len(Q) > 0 {
//探索开始
cur := Q[0]
Q = Q[1:]
if cur == end { //终点
break
}
// 依次 上 左 下 右 走一遍
for _, dir := range dirs {
// next 是0
// steps 点的值为0 (有值表示走过了)
// next 不能等于start
next := cur.add(dir)
val, ok := next.at(maze)
if !ok || val == 1 { //遇到了墙或者越界了
continue
}
// 判断是否越界或者已经走过了
val, ok = next.at(steps)
if !ok || val != 0 {
continue
}
if next == start {
continue
}
//当前的步 数
curStep, _ := cur.at(steps)
steps[next.i][next.j] = curStep + 1
// next作为 下一个要被探索的点放进队列
Q = append(Q, next)
}
}
return steps
}
//查看到达某个点所走的步数
func stepNum(steps [][]int, end point) int {
return steps[end.i][end.j]
}
// 显示迷宫地图
func showMap(maze [][]int) {
for _, row := range maze {
for _, col := range row {
fmt.Printf("%2d ", col)
}
fmt.Println()
}
}
// step 1 从文件加载地图
func readMaze(filename string) [][]int {
file, err := os.Open(filename)
if err != nil {
panic("文件不存在")
}
defer file.Close()
var row, col int
fmt.Fscanf(file, "%d %d", &row, &col)
maze := make([][]int, row)
for i := range maze {
maze[i] = make([]int, col)
for j := range maze[i] {
//fmt.Fscanf()遇到换行返回值为0,换成fmt.Fscan|https://blog.csdn.net/hp_cpp/article/details/100834645
//fmt.Fscanf(file, "%d",&maze[i][j])|这种会把换行识别为0 https://segmentfault.com/q/1010000015629978?sort=created
fmt.Fscan(file, &maze[i][j])
}
}
return maze
}
地图
6 5
0 1 0 0 0
0 0 0 1 0
0 1 0 1 0
1 1 1 0 0
0 1 0 0 1
0 1 0 0 0
例如,五子棋存盘
package main
import (
"fmt"
"github.com/huandu/xstrings"
)
type valNode struct {
row, col, val int
}
//稀疏数组
func main() {
//1 创建原始数组
var chessMap [11][11]int
chessMap[1][2] = 1 //黑
chessMap[2][3] = 2 //蓝
showMap(chessMap)
// 转为稀疏数组
// 设计结构体|
var sparseArr []valNode
//表示规模的节点|记录二位数组的行 列
sparseArr = append(sparseArr, valNode{len(chessMap), len(chessMap[0]), 0}, )
for i, v := range chessMap {
for j, v2 := range v {
if v2 != 0 {
//创建值节点
node := valNode{row: i, col: j, val: v2,}
sparseArr = append(sparseArr, node)
}
}
}
//稀疏数组
fmt.Println(xstrings.Center("稀疏数组", 20, "_"))
for i, node := range sparseArr {
fmt.Printf("%d: %-2d %-2d %2d\n", i, node.row, node.col, node.val)
}
// 恢复原始二位数组
var chessMap2 [11][11]int
for i, node := range sparseArr {
if i == 0 { //第一个节点是规模节点
continue
}
chessMap2[node.row][node.col] = node.val
}
showMap(chessMap2)
}
func showMap(chessMap [11][11]int) {
fmt.Println(xstrings.Center("showMap", 30, "_"))
for _, v := range chessMap {
for _, v2 := range v {
fmt.Printf("%d\t", v2)
}
fmt.Println()
}
fmt.Println()
}
package main
import (
"errors"
"fmt"
"github.com/huandu/xstrings"
"os"
)
//使用front 和rear记录队列前后端的下标
/**********************************
使用数组实现队列的思路
1创建一个数组array,作为队列的一个字段
2 front初始化为-1
3real,表示队列尾部,初始化为-1
4 完成队列的基本查找
Addququq 加入数据到队列
Getququ
ShowQuquq
**********************************/
type Queue struct {
maxSize int
array [4]int //数组
front int //队首
Real int //队尾
}
func (this *Queue) AddQueue(val int) (err error) {
//判断是否已满
if this.Real == this.maxSize-1 { //指向了最后
return errors.New("queue full")
}
this.Real++ //后移
this.array[this.Real] = val
return
}
func (this *Queue) ShowQueue() {
//this.Front 不包含队首的元素
//找到队首遍历到队尾|front队首,不包含第一个元素
fmt.Println(xstrings.Center("队列当前情况", 20, " "))
for i := this.front + 1; i <= this.Real; i++ {
fmt.Printf("arry=[%d]=%d\t ", i, this.array[i])
}
fmt.Println()
}
//取出队列
func (this *Queue) GetQueue() (val int, err error) {
//判断是否为空
if this.front == this.Real {
return -1, errors.New("queue empty")
}
this.front++
return this.array[this.front], nil
}
func main() {
queue := &Queue{
maxSize: 4,
front: -1,
Real: -1,
}
var (
key string
val int
)
for {
fmt.Println("1 输入add添加数据到队列")
fmt.Println("2 输入get 获取队列数据")
fmt.Println("3 输入show显示队列")
fmt.Println("4 exit")
fmt.Println()
fmt.Scanln(&key)
fmt.Println("输入的是", key)
switch key {
case "add":
fmt.Println("输入要入队列的数据")
fmt.Scanln(&val)
err := queue.AddQueue(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("加入队列OK")
}
case "get":
getQueue, err := queue.GetQueue()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("取到的数据:", getQueue)
}
case "show":
queue.ShowQueue()
case "exit":
os.Exit(1)
}
}
}
/**********************************
**********************************/
/**********************************
入队列称为addqueue ,addqueue处理需要两个步骤
1 将尾指针往后移,rear+1 front==rear 空
2 如果 尾指针rear小于等于队列的最大下标 Maxsize-1,则将数据存入rea所指的数组元素中,否则无法存入
**********************************/
package main
import (
"errors"
"fmt"
"github.com/huandu/xstrings"
"os"
)
//使用结构体还礼队列
type CircleQueue struct {
maxSize int
array [5]int
head int //队首
tail int //队列尾
}
// 入对垒
func (this *CircleQueue) Push(val int) (err error) {
//判断是否已满
if this.IsFull() {
return errors.New(" is full")
}
this.array[this.tail] = val
this.tail = (this.tail + 1) % this.maxSize //后移
return
}
//取出队列
func (this *CircleQueue) Pop() (val int, err error) {
//判断是否为空
if this.IsEmpty() {
return 0, errors.New(" is empty")
}
//head指向队首,包含队首元素
val = this.array[this.head]
this.head = (this.head + 1) % this.maxSize
return
}
func (this *CircleQueue) ShowCircleQueue() {
//this.Front 不包含队首的元素
fmt.Println(xstrings.Center("环形队列当前情况", 20, " "))
size := this.Size()
if size == 0 {
fmt.Println("队列为空")
return
}
//设计一个辅助变量,指向head
tempHead := this.head
for i := 0; i < size; i++ {
fmt.Printf("array[%d]=%d\t", tempHead, this.array[tempHead])
tempHead = (tempHead + 1) % this.maxSize
}
fmt.Println()
}
//判断是不是满
func (this *CircleQueue) IsFull() bool {
return (this.tail+1)%this.maxSize == this.head
}
//判断是否为空
func (this *CircleQueue) IsEmpty() bool {
return this.tail == this.head
}
func (this *CircleQueue) Size() int {
return (this.tail + this.maxSize - this.head) % this.maxSize
}
func main() {
CircleQueue := &CircleQueue{
maxSize: 5,
tail: 0,
head: 0,
}
var (
key string
val int
)
for {
fmt.Println("1 输入add添加数据到队列")
fmt.Println("2 输入get 获取队列数据")
fmt.Println("3 输入show显示队列")
fmt.Println("4 exit")
fmt.Println()
fmt.Scanln(&key)
fmt.Println("输入的是", key)
switch key {
case "add":
fmt.Println("输入要入队列的数据")
fmt.Scanln(&val)
err := CircleQueue.Push(val)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("加入队列OK")
}
case "get":
getCircleQueue, err := CircleQueue.Pop()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("取到的数据:", getCircleQueue)
}
case "show":
CircleQueue.ShowCircleQueue()
case "exit":
os.Exit(1)
}
}
}
//快速排序
func QuickSort(left int, right int, array *[10]int) {
l := left
r := right
// pivot 是中轴, 支点
pivot := array[(left+right)/2]
//temp := 0
//for 循环的目标是将比 pivot 小的数放到 左边
// 比 pivot 大的数放到 右边
for ; l < r; {
//从 pivot 的左边找到大于等于pivot的值
for ; array[l] < pivot; {
l++
}
//从 pivot 的右边边找到小于等于pivot的值
for ; array[r] > pivot; {
r--
}
// 1 >= r 表明本次分解任务完成, break
if l >= r {
break
}
//交换
temp:= array[l]
array[l] = array[r]
array[r] = temp
//优化
if array[l] == pivot {
r--
}
if array[r] == pivot {
l++
}
}
// 如果 1== r, 再移动下
if l == r {
l++
r--
}
// 向左递归
if left < r {
QuickSort(left, r, array)
}
// 向右递归
if right > l {
QuickSort(l, right, array)
}
}
func insertSorte(arr *[5]int) {
//完成第一次,给第二个元素找打合适的位置插入
for i := 1; i < len(arr); i++ {
insertVal := arr[i]
insertIndex := i - 1 //待插入的前一个元素下标
for insertIndex >= 0 && arr[insertIndex] < insertVal {
arr[insertIndex+1] = arr[insertIndex] //数据后移
insertIndex--
}
// 插入
if insertIndex+1 != i {
arr[insertIndex+1] = insertVal
}
}
}
//选择排序|每次选择最大的 和前面的 做交换
func SelectSort(arr *[5]int) {
for j := 0; j < len(arr)-1; j++ {
max := arr[j]
maxIndex := j
for i := j + 1; i < len(arr); i++ {
if max < arr[i] {
max = arr[i]
maxIndex = i
}
}
if maxIndex != j {
arr[j], arr[maxIndex] = arr[maxIndex], arr[j]
}
}
}
import (
"container/list"
"fmt"
)
func main() {
l := list.New()
fmt.Println(l)
//向双向链表添加元素
l.PushFront("a")
l.PushBack("b") //向最后添加元素[a,b]
l.PushBack("c") //[a,b,c]
l.InsertBefore("d", l.Back()) //back取出最后一个|[a,b,d,c]
//遍历
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
fmt.Println("双向链表头:", l.Front().Value)
fmt.Println("双向链表尾:", l.Back().Value)
// 移动元素顺序
l.MoveBefore(l.Front(), l.Back()) //把第一个移动到最后一个前面
listList(l)
l.MoveToFront(l.Back()) //把最后一个移动到最前面
}
func listList(l *list.List) {
for e := l.Front(); e != nil; e = e.Next() {
fmt.Print(e.Value, " ")
}
}
排序切片
//sort对切片排序
func SoerDemo() {
num := []int{3, 7, 1, 9}
sort.Ints(num) //升序
sort.Sort(sort.IntSlice(num)) //也是升序排列
fmt.Println("升序排序后:", num)
sort.Sort(sort.Reverse(sort.IntSlice(num))) //降序排列
fmt.Println(num)
// string
str := []string{"a", "c", "中国"}
sort.Sort(sort.Reverse(sort.StringSlice(str)))
sort.Strings(str)
fmt.Println(str)
// 该方法要求str,如果包含返回在切片的索引,如果不存在,返回该值应该在切片中哪个位置
n := sort.SearchStrings(str, "中国")
fmt.Println("中国在前片中位置", n)
}