我是靠谱客的博主 背后小熊猫,最近开发中收集的这篇文章主要介绍Go学习笔记,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • Go学习笔记
      • 一、注释
      • 二、变量
        • 1、什么叫变量
        • 2、 变量定义格式
        • 3、变量赋值
        • 4、输出格式
        • 5、变量命名规范
      • 三、基础数据类型
        • 1、布尔类型
        • 2、浮点型
        • 3、字符类型
        • 4、字符串类型
        • 5、整数类型
        • 6、常量
        • 7、iota 枚举
      • 四、运算符
        • 1、算术运算符
        • 2、关系运算符
        • 3、逻辑运算符
        • 4、赋值运算符
        • 5、其他运算符
      • 五、流程控制
        • 1、选择结构
        • 2、循环结构
      • 六、函数
        • 1、函数的定义
        • 2、匿名函数
        • 3、递归函数
      • 七、复合类型
        • 1、数组
        • 2、切片
        • 3、Map
        • 4、结构体
        • 5、指针

Go学习笔记

一、注释

  • 在代码上增加注释,方便程序代码的阅读理解
package main
import "fmt"
// 注释
注释不参与程序的编译, 可以帮助理解程序功能
// 行注释
只能注释一行
/*
块注释
可以注释多行
*/
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
// 在终端打印 hello Go
fmt.Println("hello Go")
}

二、变量

1、什么叫变量

  • 所谓的变量简单的理解就是计算机用来存储数据的。

  • 变量就是一个指定名称和类型的数据存储位置。

  • 变量的值在运行中是可以改变的

2、 变量定义格式

​ var 变量名 数据类型 声明变量

​ var 变量名 数据类型 = 值 定义

​ 变量名 := 值 自动推到类型

注意: 变量的类型不同不能进行计算,需要使用类型转换

3、变量赋值

package main
// 定义全局变量
var x string = "Hello Go"
func main() {
// 定义内部变量
var y string = "vic"
// 等价以下写法
var y string
y = "vic"
// 或者直接赋值,让GO语言推断变量的类型
var y = "vic"
// 更简洁的写法,自动推到类型,也是最常用的方法, := 定于变量的方式只能用在函数内部
x := "victor"
// 一次定义多个变量
var (
v1 int = 20
v2 string = "vic"
)
// 等价于
v1, v2 := 20, "vic"
// 定义匿名变量
// _ 下划线定义,匿名变量配合函数返回值使用才有价值,一般是丢弃数据不进行处理
_, x := 1, 2
}

4、输出格式

fmt 包 实现了类似C 语言printf 和scanf 的格式化I/O(输出输入)

https://studygolang.com/static/pkgdoc/pkg/fmt.htm#Formatter

func Println(a ...interface{})(n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
  • fmt.Println() 输出数据, 自带换行

  • fmt.Print() 输出数据,不带换行

  • fmt.Printf() 格式化输出数据

    • %d 整型
    • %s 直接输出字符串
    • %% 百分号
    • %t 布尔类型
    • %v值得默认格式
    • %+v 类似%v,但输出结构体时会添加字段名
    • %#v 值的Go语法表示
    • %T 值的类型的Go语法表示
    • %q 该值对应的双引号括起来的go语法字符串字面值
    • %c 该值对应的unicode码值或者[]byte
    • %f 浮点数输出; // %.2f 默认宽度,精度2, 32.24%
    • unsafe.Sizeof§ 可以返回 p 变量 占用的字节数 , 例如: fmt.Printf(“p 的字节数是: %d”, unsafe.Sizeof§)
  • fmt.Fprintln() 、fmt.Fprint、fmt.Fprintf 功能同上面三个函数,只不过将转换结果写入到 w 中

  • fmt.Scan() 输入数据 &变量

常用的转义字符

t	一个指标单位,实现对齐功能
n
实现换行
\	一个 
"	一个 “
r	一个回车

5、变量命名规范

1、只能以字母或者下划线开头

2、只能使用字母数字下划线

3、区分大小写

4、不能使用系统关键字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DKOk23aL-1618192318603)(images/image-20210324165246596.png)]

建议使用驼峰命名法 定义变量名称

  • 小驼峰式命名法:第一个单词以小写字母开头,第二个单词的首字母大写,例如:myName
  • 大驼峰式命名法:每一个单词的首字母都采用大写字母,例如:MyName

还有一种流行的命名方法,使用 _ 来链接所有的单词,例如:my_name

三、基础数据类型

1、布尔类型

bool 默认值 false ,其值不为真即为假,不可以用数字代表,true或者false

2、浮点型

​ float32 默认小数位置保留 7 位有效数据

​ float64 默认小数位置保留 15 位有效数据

3、字符类型

没有单独的字符型,使用byte 来保存单个字母的字符

字符 一般使用单引号,只有一个字符,转义字符除外n,打印值为 ASCII

4、字符串类型

字符串一旦赋值就不能修改,由一个或多个字符组成
双引号,会识别转义字符
反引号,以字符串原生形式输出,包括换行和特殊字符

注意: 在Go 语言中一个汉字算作 3 个字符

5、整数类型

​ int int8 int16 int32 int64 byte

6、常量

  • 程序运行期间不能被改变的量,声明需要 const
  • 常量在定义的时候必须要有初始值
  • 以大写字母开头的常量在包外是可见的,否则为包内私有
  • 变量的类型推断方式 := 不能用来定于常量

示例:

// 常规定义
const X string = "vic"
const y = "tom"
// 一次定义多个
const x,y int = 1, 2
// 一般使用如下方式定义多个常量
const (
x int = 10
y string = "vic"
)
// 如果不提供初始类型,那么视作与上一个常量值相同
const(
a = "vic"
b
// b = "vic"
)

7、iota 枚举

  • 常量声明可以使用iota 常量生成器初始化

  • const 中每新增一行常量声明将使 iota 计数一次

    示例

    // 第一个 iota 等于 0 ,每当 iota 在新的一行被使用时,它的值都会自动加 1 ;所以 a=0, b=1, c=2 可以简写如下
    const(
    a = iota
    b
    c
    )
    // 枚举 常见的iota示例
    //关键字 iota 定义常量组中从 0开始按行计数的自增枚举值
    const (
    Sunday = iota // 0
    Monday // 1,通常省略后续⾏行表达式。
    Tuesday // 2
    Wednesday // 3
    Thursday // 4
    Friday // 5
    Saturday // 6
    )
    // 使用 _ 跳过某些值
    const (
    n1 = iota
    // 0
    n2
    // 1
    _
    n4
    // 3
    )
    

四、运算符

1、算术运算符

示例:

​ 假定 A 值为10 ,B 值为20

运算符描述实例
+相加A + B 输出结果 30
-相减A - B 输出结果 -10
*相乘A * B 输出结果 200
/相除B / A 输出结果 2
%求余B % A 输出结果 0
++自增A++ 输出结果 11
自减A-- 输出结果 9

2、关系运算符

示例:

​ 假定 A 值为10 ,B 值为20

运算符描述实例
==检查两个值是否相等,如果相等返回 True 否则返回 False。(A == B) 为 False
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。(A != B) 为 True
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。(A > B) 为 False
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。(A < B) 为 True
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。(A >= B) 为 False
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。(A <= B) 为 True

3、逻辑运算符

示例:

​ 假定 A 值为 True ,B 值为 False

运算符描述实例
&&逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。(A && B) 为 False
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。(A || B) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。!(A && B) 为 True

4、赋值运算符

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值C = A + B 将 A + B 表达式结果赋值给 C
+=相加后再赋值C += A 等于 C = C + A
-=相减后再赋值C -= A 等于 C = C - A
*=相乘后再赋值C *= A 等于 C = C * A
/=相除后再赋值C /= A 等于 C = C / A
%=求余后再赋值C %= A 等于 C = C % A

5、其他运算符

运算符描述实例
&返回变量存储地址&a; 将给出变量的实际地址。
*指针变量。*a; 是一个指针变量

五、流程控制

  • 选择结构:程序依据是否满足条件,有选择的执行响应功能

  • 循环结构: 程序依据条件是否满足,循环多次执行某段代码

1、选择结构

if 语句

if 布尔表达式 {
/* 在布尔表达式为 True 时执行
*/
}

if…else 语句

if 布尔表达式 {
/* 在布尔表达式为 True 时执行
*/
} else {
/* 在布尔表达式为 False 时执行
*/
}

if 语句嵌套

在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句

if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}

示例

a := 10
b := 20
if b > a {
fmt.Printf("b: %d", b)
} else {
fmt.Printf("a: %d", a)
}
// if 里面可以在条件判断语句里面声明一个变量,这个变量的作用域只能在该条件逻辑块内,其他地方就不起作用了
if x :=1 ; x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than 10")
}
// 
c := 6
if c > 0 && (10/c) >1 {
fmt.Println("OK!")
} else {
fmt.Println("error!")
}
// 多条件判断
OS := "win"
if OS == "Centos" {
fmt.Printf("this system os: %s n", OS)
} else if OS == "Ubuntu" {
fmt.Printf("this is system os: %s n", OS)
} else {
fmt.Printf("this is system os: %s n", OS)
}
// 嵌套案例; 三只小猪称体重
a, b, c := 30, 20, 10
if a > b {
if a > c {
fmt.Println("a 最重", a)
} else {
fmt.Println("c 最重", c)
}
} else {
if b > c {
fmt.Println("b 最重", b)
} else {
fmt.Println("c 最重", c)
}
}

switch 语句

  • 用于基于不同条件执行不同的动作,每一个case分支都是唯一的,从上至下逐一测试,直到匹配为止
  • 执行的过程从上至下,直到找到匹配项,匹配项后面也不需要加break
  • 匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough
switch var1 {
case val1:
...
case val2:
...
default:
...
}

示例:

// 单独写上面赋值,或者写在switch 里面赋值,再判断,二者选其一
# x := 7
switch x :=7; x{
case 1:
fmt.Println("x :", 1)
case 4:
fmt.Println("x :", 4)
case 10:
fmt.Println("x :", 10)
default:
fmt.Println("x :", 100)
}
// switch 不提供任何判断的值,在每个case分支做测试判断
switch Num :=20; {
case Num < 0:
fmt.Println("Num < 0")
case Num > 0 && Num < 10:
fmt.Println("Num 值很小")
default:
fmt.Println("Num 值很大")
}

select 语句

  • 类似于switch语句,但是每个 case必须是一个通信操作,要么是发送要么是接收
  • select随机执行一个可运行的case 。如果没有case可执行,它将阻塞,直到有case可运行。一个默认的子句应该是总是可以运行的

语法

select {
case communication clause
:
statement(s);
case communication clause
:
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}

示例:

var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2n")
case i3, ok := (<-c3):
// same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3n")
} else {
fmt.Printf("c3 is closedn")
}
default:
fmt.Printf("no communicationn")
}

2、循环结构

# 其中expression1 和expression3 是变量声明或者函数调用返回值,
# expression2 是用来条件判断,
# expression1 在循环开始之前调用,
# expression3 在每轮循环结束之时调用
for expression1; expression2; expression3 {
// ...
}

示例

// 循环条件初始化 条件判断,循环后条件变化
for a := 0; a < 5; a++ {
fmt.Printf("a is result: %d n", a)
}
// for 配合 range 可以用于读取 slice 和 map 的数据 for 循环迭代数组
for i,x :=range num {
fmt.Printf("%d is result: %d n", i, x)
}
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %dn", i,x)
}
// 打印九九乘法表
// 外层控制行,内行控制列
for k := 1; k <= 9; k++ {
for j := 1; j < k; j++ {
fmt.Printf("%d*%d = %d
", j, k, k*j)
}
fmt.Println()
}

**break 语句 **

Break 操作是跳出当前循环,可用于 for、switch、select

	i := 0
for { // for 后面不写任何东西,循环条件永远为真,也就是死循环
i++
time.Sleep(time.Second)
// 间隔 1s 打印一次
if i == 6 { //跳出循环,如果嵌套多个循环,,就跳出最近的那个内循环
break
}
fmt.Println("i = ", i)
}

**continue 语句 **

continue 操作是跳过本次结构继续往下执行, 仅用于 for 循环语句

	i := 0
for {
i++
time.Sleep(time.Second)
if i == 3 {
continue
}
fmt.Println("i = ", i)
}

六、函数

函数调用流程:先调用后返回,先进后出

1、函数的定义

语法

func 函数名(参数列表) (返回值) {
函数体
}

特点

  • 不支持重载,一个包不能包涵同名的函数
  • 函数也是一种类型,一个函数可以赋值给变量
  • 匿名函数
  • 多返回值

定义函数名,但是参数和返回值均为空

package main
import "fmt"
// 无参无返回值函数的定义
func sayHello() {
fmt.Println("SayHello")
}
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
sayHello()
}

定义函数名及参数,返回值为空

package main
import "fmt"
// 有参无返回值函数的定义
func sayHello(a int, b int) {
fmt.Println(a + b)
}
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
sayHello(1, 2)
}

定义函数名及参数,返回一个返回值

package main
import "fmt"
// 有参有返回值函数的定义
func max(num1, num2 int) int {
// 定义局部变量
var result int
if num1 > num2 {
result = num1
} else {
result = num2
}
return result
}
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
// 调用函数并返回最大值
ret := max(10, 20)
fmt.Println(ret)
}

定义函数名及参数,且定义命名返回值

package main
import "fmt"
// 定义函数名及参数,且定义一个命名返回值
func add(a, b int) (sum int) {
sum = a + b
return
}
// 定义函数名及参数,且定义二个命名返回值
func cacl(a, b int) (sum int, cut int) {
sum = a + b
cut = a - b
return
}
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
ret1 := add(1, 2)
fmt.Println(ret1)
ret2, ret3 := cacl(3, 9)
fmt.Println(ret2, "n", ret3)
}

注意 :

在上面的函数中,sum 和 cut 是命名返回值,return 语句没有指定任何返回值。因为在函数声明的时候已经指定 sum 和 cut 是返回值,在遇到return 语句时它们会自动从函数中返回,在Go语言中,有返回值的的函数,无论是命名返回值还是普通返回值,函数中必须包涵 return 语句

有函数名,定义可变参数

  • 参数里面arg 是一个slice (切片)

  • 通过arg(index)依次访问所有参数

  • 通过len(arg) 来判断传递参数的个数

    // 0 个或 多个参数
    func add(arg...int) int{
    return
    }
    // 1 个或 多个参数
    func add(a int, arg...int) int{
    return
    }
    // 2 个或 多个参数
    func add(a, b int, arg...int) int{
    return
    }
    

示例

package main
import (
"fmt"
)
// 传递值进行相加
func add(a int, arg...int) int {
sum := a
for i :=0; i < len(arg); i++ {
//打印 后面参数的值
fmt.Printf("可变参数: %dn",arg[i])
sum +=arg[i]
}
return sum
}
// 传递字符串,结果拼接
func connect(a string, arg...string) (reslut string) {
reslut = a
for i := 0; i < len(arg); i++ {
reslut +=arg[i]
}
return
}
func main() {
sum := add(10, 20, 30)
fmt.Printf("result is :%dn", sum)
res :=connect("Hi", " ", "Victor")
fmt.Println(res)
}

函数也是一种类型

package main
import (
"fmt"
)
// 在go 中,函数也是一种数据类型
// 可以赋值给一个变量,则该变量就是一个函数类型的变量了,通过变量可以对函数进行调用
func sum(a, b int) int {
return a + b
}
func main() {
c := sum
fmt.Printf("c 的类型是:%T nsum 的类型是:%T n", c ,sum)
res := c(1,2) // 等价
res := sum(1,2)
fmt.Println("res 的值是: ",res)
}

2、匿名函数

  • 匿名函数即没有名字的函数

  • 如果某个函数只是希望调用异常,那么就可以使用匿名函数,当然也可以实现多次调用

示例

package main
import "fmt"
// main 叫做主函数 是程序的主入口
程序有且只有一个主函数
func main() {
// 无参匿名函数
func() {
fmt.Println("this is 匿名函数")
}() // 末尾使用 () 表示此匿名函数被调用
// 无参有返回值的匿名函数
func() int {
a := 10
fmt.Println(a)
return a
}()
// 匿名函数:二个数求和,先赋值给一个变量再调用
ret := func(a1, a2 int) int {
return a1 + a2
}(10, 20)
fmt.Printf("ret type => %T, ret=%d n", ret, ret)
// 第二种匿名函数定义方式
f := func(a1, a2 int) int {
return a1 - a2
}
f1 := f(10, 5)
fmt.Printf("f type => %T, f1 type => %T n", f, f1)
fmt.Println(f1)
}

3、递归函数

  • 当一个函数在其函数体内调用自身,则称为递归函数

示例一

func recusive(){
fmt.Println("Hello ")
time.Sleep(time.Second)
recusive() //调用函数自身,实现递归
}
func main(){
recusive
}

示例二

func test(n int){
if n > 5 {
n--
// 递归必须向退出条件逼近,否则就是无限循环调用
test(n)
}else{
fmt.Println("n => ",n)
}
}
func main(){
test(5)
}

示例三

// 功能 阶乘 4 * 3 * 2 * 1
func mul(n int) int {
if n == 1 {
return 1
}
return mul(n-1) * n
}
func main() {
n := mul(4)
fmt.Println(n)
}

示例四

// 递归实现数字累加
//递归实现1+2+3+……100
func add1(n int) int {
if n == 100 {
return 100
}
return n + add1(n + 1)
}
func add2(i int) (sum int) {
if i == 1 {
return 1
}
return i + add2(i - 1)
}
func main() {
sum1 := add1(1)
fmt.Printf("sum1 = %dn", sum1)
sum2 := add2(100)
fmt.Printf("sum2 = %d", sum2)
}

七、复合类型

1、数组

用来存储集合的数据

​ 数组的声明和初始化

​ 1、声明存储数据的类型

​ 2、存储元素的数量,也就是数组的长度

​ 3、数组是类型相同元素的集合,Go 不允许在数组中混合使用不同类型的元素

​ 4、数组中的所有元素都被自动赋值为元素类型的 0 值

​ 5、数组的索引从 0 开始到 length-1 结束

数组的定义

  • 第一种方式

    var <数组名称> [<数组长度>]<数组元素类型>
    示例:
    // arr[0] 表示数组 arr 的第一个元素,arr[1] 表示数组的第二个元素,等等依次增加
    var arr [5]
    arr[0] = 4
    arr[1] = 43
    arr[2] = 3423
    arr[3] = 234
    arr[4] = 654
    
  • 第二种方式

    var <数组名称> = [<数组长度>]<数组元素类型>{元素1, 元素2, ...}
    示例:
    var arr = [3]{32, 323, 765}
    GO提供了 := 操作符,可以在创建数组的时候直接初始化赋值
    arr := [3]{32, 323, 765}
    
  • 第三种方式

    声明数组的时候可以忽略数组的长度使用 ... 代替,让编辑器自动推到数组的长度
    var <数组名称> = [...]<数组元素类型>{元素1, 元素2, ...}
    示例:
    var arr = [...]{32342, 324, 43, 443}
    或者
    arr := [...]{32342, 324, 43, 443}
    
  • 第四种方式

    给数组指定的索引指定初始化的值,其他为 0
    var <数组名称> = [...]<数组元素类型>{索引1:元素1, 索引2:元素2, ...}
    示例:
    var arr = [...]{3:232, 6:4353}
    或者
    arr := [...]{3:232, 6:4353}
    

示例:

​ 循环打印数组中的值

package main
import (
"fmt"
)
func main() {
// 循环打印数组中的值
array :=[...]int{1,2,3,4}
for i :=0; i < len(array); i++ {
fmt.Printf("%d 值: %d
n", i, array[i])
}
// 使用 for range 循环
array1 :=[...]string{"name","Victor","age"}
for k,v :=range array1 {
fmt.Printf("索引:%d ,值:%s n", k,v)
}
// 不要索引
for _,i :=range array1 {
fmt.Printf("值:%s n", i)
}
}

在数组中寻找最大 or 最小值

package main
import (
"fmt"
)
func main() {
arr := [10]int{10, 4, 200, 43, 20, 324, 32, 90, 34, 31}
// 找出最大值 or 最小值
max := arr[0]
for i := 1; i < len(arr); i++ {
if max < arr[i] {
max = arr[i]
}
}
fmt.Println(max)
}
func main() {
// 求出一个数组里面的最大值,并得到对应的下标
// 1.声明一个数组
// 2.假定第一个元素就是最大值,下标 0
// 3.然后从第二个元素开始循环比较,如果发现有更大则替换
var myArr [...]int = [...]int {30, -2, 3, 20, 15}
max := myArr[0]
maxIndex := 0
for i := 1; i < len(myArr); i++{
// 从第二个元素开始比较,如果有更大,则交换
if max < myArr[i] {
max = myArr[i]
maxIndex = i
}
}
// 打印结果
fmt.Printf("max= %v ; maxIndex= %v", max, maxIndex)
}

数组的查找

package main
import (
"fmt"
)
func main() {
// 定义数组
names := [4]string{"tom", "vic", "ccg", "vc"}
var inName string
fmt.Println("请输入要查找的名字=》")
fmt.Scanln(&inName)
// 顺序查找 第一种方式
for i := 0; i < len(names); i++ {
if inName == names[i] {
fmt.Println("找到 :", inName, "下标:", i)
break
} else if i == (len(names) - 1){
fmt.Println("没有找到 :", inName)
}
}
// 顺序查找 第二种方式
index := -1
for i := 0; i < len(names); i++ {
if inName == names[i] {
index = i // 讲找到值的对应下标赋给 index
break
}
}
if index != -1 {
fmt.Println("找到 :", inName, "下标:", index)
} else {
fmt.Println("没有找到 :", inName)
}
}

冒泡排序

示例[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YpAXvOF8-1618192318605)(images/image-20210331142932764.png)]

package main
import (
"fmt"
)
func main() {
arr := [10]int{10, 4, 200, 43, 20, 324, 32, 90, 34, 31}
// 冒泡排序
// 外层控制行
for k := 0; k < len(arr)-1; k++ {
// 内层控制列
for j := 0; j < len(arr)-1-k; j++ {
// 比较二个相邻元素,满足条件就交换数据
// 升序排列使用大于号; 降序排列使用小于号
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
fmt.Println(arr)
}

数组作为函数参数和返回值

package main
import (
"fmt"
)
// 数组作为函数参数和返回值
func bubbleSort(array [10]int) [10]int {
for k := 0; k < len(array); k++ {
for j := 0; j < len(array)-1-k; j++ {
// 比较二个相邻元素,满足条件就交换数据
if array[j] < array[j+1] {
array[j], array[j+1] = array[j+1], array[j]
}
}
}
return array
}
func main() {
arr := [10]int{10, 4, 200, 43, 20, 324, 32, 90, 34, 31}
arr = bubbleSort(arr)
fmt.Println(arr)
}

多维数组

多维数组的定义

二维数组
var	数组名 [行数][列数] 数据类型

示例

package main
import "fmt"
func main() {
// 多维数组
// 定义了一个数组 A ,A 数组里面包涵了 2 个元素, 但是每个元素里面又包涵了 3 个元素
A := [2][3]{
{1, 3, 4},
{34, 43, 54}
}
fmt.Println(A)
}

多维数组的遍历

package main
import (
"fmt"
)
func main() {
var arr = [3][3]int {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
// for 循环 来遍历
for j := 0; j < len(arr); j++ {
for k :=0; k < len(arr[j]); k++{
fmt.Printf("%v t", arr[j][k])
}
fmt.Println()
}
// for-range 来遍历, 使用 _ 省略索引的打印
for _,x := range arr {
for _,y := range x {
fmt.Printf("%v t", y)
}
fmt.Println()
}
}

示例

fncu main() {
// 创建一个 byte 类型的26元素的数组,分别放置 A-Z
// 使用for 循环打印
//使用for 循环,利用字符可以进行运算的特点来进行赋值 'A' +1 -> 'B'
var myChars [26]byte
for i := 0; i < len(26); i++{
myChars[i] = 'A' + byte(i) // 需要将 i 装换成 byte 类型
}
for i := 0; i< 26; i++{
// %c 该值对应的unicode码值
fmt.Piintf("%c", myChars[i])
}
}

示例

func main() {
// 求数组的和及平均值
// 1.定义数组
// 2.求和
// 3.求平均值
var rSum [5]int = [...]int {20, -1, 10, 11}
sum := 0
for _, v := range rSum {
// 累计求和
sum += v
}
// 求平均值
fmt.Printf("sum= %v ; 平均值= %v", sum, float64(sum) / float64(len(v)))
}

示例

package main
import (
"time"
"math/rand"
"fmt"
)
// 随机生成 五个随机数,并将其反转打印
// 1.随机生成五个随机数,rand.Intn()
// 2.存到数组
// 3.反转打印
func main() {
var intArr [5]int
// 为了每次生成的随机数不一样,需要给一个seed值
rand.Seed(time.Now().UnixNano())
for i :=0; i < len(intArr); i++ {
intArr[i] = rand.Intn(100)
}
fmt.Println(intArr)
for x,y := 0, len(intArr) -1; x < y; x ,y = x + 1, y - 1{
intArr[x], intArr[y] = intArr[y], intArr[x]
}
fmt.Println(intArr)
}

2、切片

切片是建立在数组之上的更方便、更灵活、更强大的数据结构,切片不存储任何元素而只是对现有数组的引用

切片对象非常小,是因为它是只有 3 个字段的数据结构:

  • 指向底层数组的指针

  • 切片的长度

  • 切片的容量

使用内置的 make 函数时,需要传入一个参数指定切片的长度,如:切片的长度是 6,这时候容量也是 6 ;当然也可以单独指定切片的容量

注意:容量必须 (cap) >= 长度(len) ,不能创建长度大于容量的切片

切片和数组的区别

定义数组必须写元素个数,而切片不需要写元素个数

// 数组
array := [4]int{1, 2, 3, 4}
// 切片
slice := []int{1, 2, 3, 4}

通过 make 创建切片

  • 通过 make 创建的切片可以指定切片的大小和容量

  • 如果没有给切片赋值,那么就会使用默认值(int、float => 0,string => “”,bool => false)

  • 通过make创建的切片对应的数组是由make底层维护,对外不可见,只能通过 slice访问各个元素

基本语法

var
切片名 []type = make([], len, [cap])
// type 数据类型
// len
大小,即长度
// cap
容量,(容量必须 >= 长度)
// 没有赋值,默认都是 0
var slice []int = make([]int, 5, 10)
// 简写
slice := make([]int, 5, 10)
slice := make([]int, 5)
// 赋值
slice[2] = 5

切片直接引用数组

// 从下标 startIndex 开始,取到下标 endIndex, 但是数据不包含 arr[endIndex]
var slice = arr[startIndex:endIndex]
var slice = arr[0:end]
// 简写 var slice = arr[:end]
var slice = arr[start:len(arr)]
// 简写 var slice = arr[start:]
var slice = arr[0:len(arr)]
// 简写 var slice = arr[:]

切片简单操作示例

// 声明一个切片并追加数据, 使用内置函数 append
var vic []string
vic = append(vic, "Go")
// 同时声明并初始化一个切片
v := []string{"GO", "JAVA"}
fmt.Println(v)
// 切片长度是可变的;使用内置函数 make 创建长度不为 0 的切片
s := make([]int, 5)
fmt.Println(s)
// 取值和赋值,和数组一样
s[1] = 111
s[3] = 333
fmt.Println(s)
fmt.Println(s[4])
// 使用内置函数 len 获取切片的长度
fmt.Println(len(s))
// append 函数不会改变原切片,而是生成了一个新的切片,需要用原来的切片接收这个新切片
s = append(s, 222, 444)
// 把一个切片追加到另一个切片, 通过 ... 操作符
x := []int{1, 2, 3, 4}
y := []int{11, 22, 33}
x = append(x ,y...)
// 切片也支持从一个切片拷贝元素到另一个切片,使用内置函数 copy
k := []string{"a", "b"}
j := []string{"x", "y"}
copy(k, j) // 拷贝切片 j 中的元素到 k 中
fmt.Println(k)

切片的迭代

// 切片是一个集合,可以使用 for range 循环迭代
S1 := []string{"Go", "JAVA", "Python"}
for k,v := range S1{
fmt.Printf("索引 %d => 值 %s n", k, v)
}
// 如果不打印索引,可以使用 _ 来忽略
for _,v := range S1{
fmt.Printf("值 %s n",
v)
}
// 使用传统 for 循环,配合内置函数 len 
for i :=0; i < len(S1); i++{
fmt.Println("值:", S1[i])
}

多维切片

// 同数组一样,切片也可以有多个维度,并且可以不固定长度
S2 := [][]string{
{"C", "JAVA"},
{"Go", "Perl"}
}
for _,v := range S2 {
fmt.Println(v)
}

切片作为函数参数

package main
import "fmt"
func test(v1 []string) {
fmt.Println(v1[1])
fmt.Printf("%v n", v1)
}
func main() {
v1 := []string{"Go", "Java"}
test(v1)
}

切片作为函数参数和返回值

package main
import "fmt"
func test(v1 []int) (v2 []int) {
v2 = v1[0:2]
fmt.Printf("v2数据: %v n", v2)
return
}
func main() {
v1 := []int{11, 22, 33, 44}
fmt.Println("v1数据:", v1)
test(v1)
}

3、Map

  • Map 是 Go 语言中的内置类型,它将 键与值 绑定到一起,可以通过键获取相应的值
  • Map类似Python中字典的概念,是一种无序的键值对集合
  • 可以通过 Key 来快速检索数据,key 类似索引,指向数据的值
  • map的长度是自动扩容的
  • map中的数据是无序存储的
  • 在map 中键不允许重复必须是唯一的,值可以重复

基本语法

// map 赋值方式,必须先声明、再初始化,最后赋值
var Victor map[string]string
Victor = make(map[string]string)
Victor["name"] = "Tom"
// 或者
M := make(map[string]int)
M["age"] = 20
// 直接初始化并赋值
M1 := map[string]int{
"age": 20,
"sex": 18
}
// 指定 map 长度,一般直接省略
M2 := make(map[string]string, 10)

map 增改删

// 向 map 中插入数据,语法和数组类似
shop := make(map[string]int)
shop["Apple"] = 20
shop["Orange"] = 15
shop["Banana"] = 9
// 修改数据
shop["Apple"] = 30
// 删除数据,使用内置函数 delete
// delete(map, key) 用于删除 map 中的 key,delete 函数没有返回值
delete(shop, "Banana")

遍历 map

shop := map[string]int{
"Apple": 30,
"Banana": 15,
}
// 使用 range 循环
for k,v := range shop{
fmt.Println(k,v)
}
// 判断 key 是否存在
if v, ok := shop["Apple"]; ok{
fmt.Println("Apple:", v)
}else {
fmt.Println("Key is Not found")
}

map作为函数参数

func test(m map[int]string){
m[101] = "孙悟空"
fmt.Println(m)
}
func main() {
People := map[int]string{
101: "关羽",
102: "张飞",
103: "刘备",
}
fmt.Println(People)
test(People)
}

map 值排序

shop := map[30]string{
30: "tea",
15: "coffee",
50:"sweet",
}
var keys []int
for k,_ := range shop{
keys = append(keys, k)
}
fmt.Println(keys)
sort.Ints(keys[:])
fmt.Println(keys)
for _,v := keys{
fmt.Println(v, shop["v"])
}

统计单词出现的次数

s := "how to contribute who to contact about how"
// 定义 map 存放单词
wordCount := make(map[string]int)
// 分割字符串中的单词
words := strings.Split(s, " ")
// 遍历统计单词
for _, w := range words{
if v, ok := wordCount[w]; ok {
// map 中有这个单词的统计出现就 +1
wordCount[w] = v + 1
}else {
// map 中没有这个单词的统计记录就等于 1
wordCount[w] 1
}
}
// 打印单词出现的次数
for k,v := range wordCount {
fmt.Println(k,v)
}

双层嵌套

// 存放学生信息,学生 name、age
studentMap := make(map[string]map[string]string)
// 添加数据
studentMap["stu1"] = make(map[string]string)
studentMap["stu1"]["Name"] = "vic"
studentMap["stu1"]["Age"] = "20"
studentMap["stu2"] = make(map[string]string)
studentMap["stu2"]["Name"] = "Tom"
studentMap["stu2"]["Age"] = "18"
fmt.Println(studentMap)
fmt.Println(studentMap["stu1"])
fmt.Println(studentMap["stu1"]["Name"])
// 定义字典,key 再定义字典 key,键值为切片
City := make(map[string]map[string][]string)
// 如果插新加入的元素也是个 map 的话需要再次 make()
Area := make(map[string][]string)
Area["朝阳区"] = []string{"工业大学", "语言大学", "传媒大学"}
Area["海淀区"] = []string{"清华大学", "理工大学", "农业大学"}
City["北京"] = Area
for k, v := range Area {
fmt.Println(k, v)
for x, y := range v {
fmt.Println(x, y)
}
}

三层嵌套

//定义国家
Country := make(map[string]map[string]map[string][]string)
//定义城市
City := make(map[string]map[string][]string)
//定义区
Area1 := make(map[string][]string)
Area2 := make(map[string][]string)
//赋值
Area1["朝阳区"] = []string{"工业大学", "语言大学", "传媒大学",}
Area1["海淀区"] = []string{"清华大学", "理工大学", "农业大学",}
Area2["黄浦区"] = []string{"复旦大学", "同济大学"}
Area2["静安区"] = []string{"交通大学", "财经大学"}
City["北京"] = Area1
City["上海"] = Area2
Country["中国"] = City
for k, v :=range City{
fmt.Println(k, v)
for x, y :=range v {
fmt.Println(x, y)
for i := range y {
fmt.Println(y[i])
}
}
}

4、结构体

5、指针

最后

以上就是背后小熊猫为你收集整理的Go学习笔记的全部内容,希望文章能够帮你解决Go学习笔记所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(75)

评论列表共有 0 条评论

立即
投稿
返回
顶部