GO语言基础

GO语言基础

(有点开发基础是真的有点懒得写)

包声明

package main   //包名,主函数

引入包

import "fmt"   //格式化IO

函数

func main(){}     //主函数

变量

var a int   //不初始化默认为0 布尔则为false
var b string = "默认赋值"
var c = "字符串"  //自动判断变量类型
d := 123   //一般用于局部变量定义
var (
  e int
  f string
)          //一般用于全局变量声明

语句 & 表达式

fmt.Println("测试")   //打印内容

注释

/*
注释
*/
// 注释

简单实例

package main

import "fmt"

func main(){
   fmt.Println("测试")
}

常用语法(关键字)

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar
25个关键字或保留字
appendboolbytecapclonecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16int32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr
36个预定义标识符

Go语言空格

空格常用于分隔标识符、 关键字、运算符和表达式、提高代码可读性。

其中,变量的声明必须用空格隔开:

var a int
const Pi float64 = 3.14159265358979323846

关键字和表达式之间也要使用空格:

if a > 0 {
    fmt.Println(a)
}

在调用函数时,函数名和左边等号之间要用空格,参数之间也要用空格。

result := add(2, 3)

Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。

Printf 根据格式化参数生成格式化的字符串并写入标准输出。

package main

import (
    "fmt"
)

func main() {
   // %d 表示整型数字,%s 表示字符串
    var stockcode=456
    var enddate="2024-6-12"
    var url="Code=%d&endDate=%s"
    var target_url=fmt.Sprintf(url,stockcode,enddate)
    fmt.Println(target_url)
}

输出结果:

Code=456&endDate=2024-6-12

实例:

package main

import (
    "fmt"
)

func main() {
   // %d 表示整型数字,%s 表示字符串
    var stockcode=456
    var enddate="2024-6-12"
    var url="Code=%d&endDate=%s"
    fmt.Printf(url,stockcode,enddate)
}

输出结果:

Code=456&endDate=2024-6-12

数据类型:

序号类型和描述
1布尔型
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型
整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
3字符串类型:
字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
4派生类型:
包括:(a) 指针类型(Pointer)
(b) 数组类型
(c) 结构化类型(struct)
(d) Channel 类型
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface)
(h) Map 类型
4种数据类型

数字类型:

序号类型和描述
1uint8
无符号 8 位整型 (0 到 255)
2uint16
无符号 16 位整型 (0 到 65535)
3uint32
无符号 32 位整型 (0 到 4294967295)
4uint64
无符号 64 位整型 (0 到 18446744073709551615)
5int8
有符号 8 位整型 (-128 到 127)
6int16
有符号 16 位整型 (-32768 到 32767)
7int32
有符号 32 位整型 (-2147483648 到 2147483647)
8int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
也有基于架构的类型,例如:int、unit、uintptr

浮点数

序号类型和描述
1float32
IEEE-754 32位浮点型数
2float64
IEEE-754 64位浮点型数
3complex64
32 位实数和虚数
4complex128
64 位实数和虚数

其他数字类型

序号类型和描述
1byte
类似 uint8
2rune
类似 int32
3uint
32 或 64 位
4int
与 uint 一样大小
5uintptr
无符号整型,用于存放一个指针

常量

定义格式:

const abc [type] = value

const a string = "abc"    //定义类型
const b = "abc"            //自动定义类型

const (
   q = "abc"
   w = len(q)
   e = unsafe.Sizeof(a)
)
//结果为 abc 3 16

//unsafe.Sizeof返回的是数据类型的大小
//string在Go中并不是直存类型,而是一个结构体类型:
type StringHeader struct {
        Data uintptr
        Len  int
}

iota

特殊常量,可以备注编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

枚举值用法:

const (
    a = iota
    b = iota
    c = iota
)
const (
    a = iota
    b
    c
)
及a=0,b=1,c=2

实例1:

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

//运行结果 0 1 2 ha ha 100 100 7 8

实例2

package main

import "fmt"
const (
    i=1<<iota
    j=3<<iota
    k
    l
)

func main() {
    fmt.Println("i=",i)
    fmt.Println("j=",j)
    fmt.Println("k=",k)
    fmt.Println("l=",l)
}

//运行结果:
//i= 1
//j= 6
//k= 12
//l= 24
//iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。

解释:

  • i=1:左移 0 位,不变仍为 1。
  • j=3:左移 1 位,变为二进制 110,即 6。
  • k=3:左移 2 位,变为二进制 1100,即 12。
  • l=3:左移 3 位,变为二进制 11000,即 24。

注:<<n==*(2^n)

算数运算符

算数运算符描述实例
+相加A + B =30
相减A – B = -10
*相乘A * B = 200
/相除B / A = 2
%求余B % A = 0
++自增A++ 为11
自减A– 为9
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
A=10 B=20

逻辑运算符

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

位运算符

运算符描述实例
&按位与运算符”&”是双目运算符。 其功能是参与运算的两数各对应的二进位相与。(A & B) 结果为 12, 二进制为 0000 1100
!按位或运算符”|”是双目运算符。 其功能是参与运算的两数各对应的二进位相或(A | B) 结果为 61, 二进制为 0011 1101
^按位异或运算符”^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。(A ^ B) 结果为 49, 二进制为 0011 0001
<<左移运算符”<<“是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<“右边的数指定移动的位数,高位丢弃,低位补0。A << 2 结果为 240 ,二进制为 1111 0000
>>右移运算符”>>”是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>”左边的运算数的各二进位全部右移若干位,”>>”右边的数指定移动的位数。A >> 2 结果为 15 ,二进制为 0000 1111
A=60 B=13

赋值运算符

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值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
<<=左移后赋值C <<= 2 等于 C = C << 2
>>=右移后赋值C >>= 2 等于 C = C >> 2
&=按位与后赋值C &= 2 等于 C = C & 2
^=按位异或后赋值C ^= 2 等于 C = C ^ 2
|=按位或后赋值C |= 2 等于 C = C | 2

其他运算符

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

运算符优先级

优先级运算符
5/ % << >> & &^
4– | ^
3== != < <= > >=
2&&
1||

条件语句

语句描述
ifif 语句 由一个布尔表达式后紧跟一个或多个语句组成。
if elseif 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
if 嵌套你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。
switchswitch 语句用于基于不同条件执行不同动作。
selectselect 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
go没有三目运算符,不支持?:形式的条件判断

循环语句

循环类型描述
for重复执行语句块
循环嵌套在 for 循环中嵌套一个或多个 for 循环

循环控制语句

控制语句描述
break经常用于中断当前 for 循环或跳出 switch 语句
continue跳过当前循环的剩余语句,然后继续进行下一轮循环。
goto将控制转移到被标记的语句。

无限循环

package main

import "fmt"

func main() {
    for true  {
        fmt.Printf("这是无限循环。\n");
    }
}

函数

函数定义:

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,参数列表和返回值类型构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

实例

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {   //第一个int是num2    第二个int是函数返回值
   /* 声明局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

函数调用

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
   var ret int

   /* 调用函数并返回最大值 */
   ret = max(a, b)

   fmt.Printf( "最大值是 : %d\n", ret )
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 定义局部变量 */
   var result int

   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result 
}

函数范围多个值

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("445", "123")
   fmt.Println(a, b)
}

函数参数

传递类型描述
值传递值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

函数用法

函数用法描述
函数作为另外一个函数的实参函数定义后可作为另外一个函数的实参数传入
闭包闭包是匿名函数,可在动态编程中使用
方法方法就是一个包含了接受者的函数

变量作用域

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数(形参)

实例:

package main

import "fmt"

/* 声明全局变量 */
var a int = 20;

func main() {
   /* main 函数中声明局部变量 */
   var a int = 10
   var b int = 20
   var c int = 0

   fmt.Printf("main()函数中 a = %d\n",  a);
   c = sum( a, b);
   fmt.Printf("main()函数中 c = %d\n",  c);
}

/* 函数定义-两数相加 */
func sum(a, b int) int {
   fmt.Printf("sum() 函数中 a = %d\n",  a);
   fmt.Printf("sum() 函数中 b = %d\n",  b);

   return a + b;
}

运行结果:

main()函数中 a = 10
sum() 函数中 a = 10
sum() 函数中 b = 20
main()函数中 c = 30

初始化局部和全部变量

数据类型初始化默认值
int0
float320
pointernil

数组

声明数组语法格式:

var arrayName [size]dataType

var abc [10]int      //声明一个长度为10的数组abc,类型为int
var abc = [5]int{1,2,3,4,5}     //初始化
abc := [5]int{1,2,3,4,5}        //初始化

//注:在Go语言中,数组的大小是类型的一部分,不同大小的数组是不兼容的,[5]int和[10]int是不同的类型

//不确定长度可以使用...
var abc = [...]int{1,2,3}
abc := [...]int{1,2,3,4,5}

//指定初始化,将索引1和4的元素初始化
var abc = [5]int{1:3,4:11}
初始化数组中 {} 中的元素个数不能大于 [] 中的数字。

//如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小

指针

go语言中,取地址符是&

package main

import "fmt"

func main() {
   var a int = 10   

   fmt.Printf("变量的地址: %x\n", &a  )
}

//运行结果:变量的地址:20818a220

指针的定义

一个指针变量指向了一个值的内存地址。

类似于变量和常量,在使用指针前需要声明指针。指针声明格式如下:

var var_name *var-type
//var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

指针使用流程:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。
package main

import "fmt"

func main() {
   var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &a  )

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip )
}
//a 变量的地址是: 20818a220
//ip 变量储存的指针地址: 20818a220
//*ip 变量的值: 20

空指针

当一个指针被定义后没有分配到任何变量时,它的值为 nil。

nil 指针也称为空指针。

nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。

一个指针变量通常缩写为 ptr。

package main

import "fmt"

func main() {
   var  ptr *int

   fmt.Printf("ptr 的值为 : %x\n", ptr  )
}
//ptr 的值为 : 0

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

结构体

这个跟其他语言的结构体基本上一致。

定义结构体

type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}

定义了结构体后,声明变量的语法:

variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

实例:

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}


func main() {

    // 创建一个新的结构体
    fmt.Println(Books{"Go 语言", "test", "测测", 123456})

    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "test", subject: "测测", book_id: 456789})

    // 忽略的字段为 0 或 空
   fmt.Println(Books{title: "Go 语言", author: "test"})
}

输出结果:
{Go 语言 test Go 测测 123456}
{Go 语言 test Go 测测 456789}
{Go 语言 test  0}

访问结构体成员

结构体.成员名

实例:

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "test1"
   Book1.subject = "测测"
   Book1.book_id = 123456

   /* book 2 描述 */
   Book2.title = "坏鸟"
   Book2.author = "test2"
   Book2.subject = "测测"
   Book2.book_id = 456789

   /* 打印 Book1 信息 */
   fmt.Printf( "Book 1 title : %s\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)

   /* 打印 Book2 信息 */
   fmt.Printf( "Book 2 title : %s\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}

运行结果:
Book 1 title : Go 语言
Book 1 author : test1
Book 1 subject : 测测
Book 1 book_id : 123456
Book 2 title : 坏鸟
Book 2 author : test2
Book 2 subject : 测测
Book 2 book_id : 456789

结构体作为函数参数

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "test1"
   Book1.subject = "测测"
   Book1.book_id = 123456

   /* book 2 描述 */
   Book2.title = "坏鸟"
   Book2.author = "test2"
   Book2.subject = "测测"
   Book2.book_id = 456789

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}

func printBook( abc Books ) {
   fmt.Printf( "Book title : %s\n", abc.title)
   fmt.Printf( "Book author : %s\n", abc.author)
   fmt.Printf( "Book subject : %s\n", abc.subject)
   fmt.Printf( "Book book_id : %d\n", abc.book_id)
}

运行结果:
Book title : Go 语言
Book author : test1
Book subject : 测测
Book book_id : 123456
Book title : 坏鸟
Book author : test2
Book subject : 测测
Book book_id : 456789

结构体指针

结构体指针格式如下:

var struct_pointer *Books
 
以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置于结构体变量前:

struct_pointer = &Book1
使用结构体指针访问结构体成员,使用 "." 操作符:

struct_pointer.title

实例:

package main

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "test1"
   Book1.subject = "测测"
   Book1.book_id = 123456

   /* book 2 描述 */
   Book2.title = "坏鸟"
   Book2.author = "test2"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 456789

   /* 打印 Book1 信息 */
   printBook(&Book1)

   /* 打印 Book2 信息 */
   printBook(&Book2)
}
func printBook( book *Books ) {
   fmt.Printf( "Book title : %s\n", book.title)
   fmt.Printf( "Book author : %s\n", book.author)
   fmt.Printf( "Book subject : %s\n", book.subject)
   fmt.Printf( "Book book_id : %d\n", book.book_id)
}

运行结果:
Book title : Go 语言
Book author : test1
Book subject : 测测
Book book_id : 123456
Book title : 坏鸟
Book author : test2
Book subject : 测测
Book book_id : 456789

切片

Go语言切片是对数组的抽象,在Go语言中,数组的长度是不可改变的,为了使其具有灵活性,Go语言提供了一个内置类型切片(“动态数组”),可以理解为不写长度的数组就是切片。

定义切片

切片不需要说明长度

var identifier []type

var slice1 []type = make([]type, len)

也可以简写为

slice1 := make([]type, len)

也可以指定容量,其中 capacity 为可选参数,意思是最大长度
make([]T, length, capacity)
这里 len 是数组的长度并且也是切片的初始长度

切片初始化
s :=[] int {1,2,3 } 

直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
s := arr[:] 

初始化切片 s,是数组 arr 的引用。

s := arr[startIndex:endIndex] 
将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。

s := arr[startIndex:] 
默认 endIndex 时将表示一直到arr的最后一个元素。

s := arr[:endIndex] 
默认 startIndex 时将表示从 arr 的第一个元素开始。

s1 := s[startIndex:endIndex] 
通过切片 s 初始化切片 s1。

s :=make([]int,len,cap) 
通过内置函数 make() 初始化切片s,[]int 标识为其元素类型为 int 的切片。

len()和cap()

len()获取长度,cap()测量切片最长可以达到多少。

package main

import "fmt"

func main() {
   var numbers = make([]int,3,5)

   printSlice(numbers)
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

输出结果:
len=3 cap=5 slice=[0 0 0]

空切片(nil)

一个切片在未初始化时默认为nil,长度为0

package main

import "fmt"

func main() {
   var numbers []int

   printSlice(numbers)

   if(numbers == nil){
      fmt.Printf("切片是空的")
   }
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

输出结果:
len=0 cap=0 slice=[]
切片是空的

切片截取

package main

import "fmt"

func main() {
   /* 创建切片 */
   numbers := []int{0,1,2,3,4,5,6,7,8}   
   printSlice(numbers)

   /* 打印原始切片 */
   fmt.Println("numbers ==", numbers)

   /* 打印子切片从索引1(包含) 到索引4(不包含)*/
   fmt.Println("numbers[1:4] ==", numbers[1:4])

   /* 默认下限为 0*/
   fmt.Println("numbers[:3] ==", numbers[:3])

   /* 默认上限为 len(s)*/
   fmt.Println("numbers[4:] ==", numbers[4:])

   numbers1 := make([]int,0,5)
   printSlice(numbers1)

   /* 打印子切片从索引  0(包含) 到索引 2(不包含) */
   number2 := numbers[:2]
   printSlice(number2)

   /* 打印子切片从索引 2(包含) 到索引 5(不包含) */
   number3 := numbers[2:5]
   printSlice(number3)

}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

运行结果:
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=7 slice=[2 3 4]

append()和copy()

添加新元素append(),复制切片copy()

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

   /* 允许追加空切片 */
   numbers = append(numbers, 0)
   printSlice(numbers)

   /* 向切片添加一个元素 */
   numbers = append(numbers, 1)
   printSlice(numbers)

   /* 同时添加多个元素 */
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)

   /* 创建切片 numbers1 是之前切片的两倍容量*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)

   /* 拷贝 numbers 的内容到 numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

范围

跟python的差不多,一般用于for循环迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap {
    newMap[key] = value
}

只读key:
for key := range oldMap
for key, _ := range oldMap

只读value:
for _, value := range oldMap
类似于python的:
oldMap = {1:"a", 2: "b",3: "c"}
for key,value in oldMap.items():
     abc[key] = value

实例

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
   for i, v := range pow {
      fmt.Printf("2**%d = %d\n", i, v)
   }
}

运行结果:
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128
package main
import "fmt"
func main() {
    //这是我们使用 range 去求一个 slice 的和。使用数组跟这个很类似
    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)
    //在数组上使用 range 将传入索引和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
    for i, num := range nums {
        if num == 3 {
            fmt.Println("index:", i)
        }
    }
    //range 也可以用在 map 的键值对上。
    kvs := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }

    //range也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
    for i, c := range "go" {
        fmt.Println(i, c)
    }
}

运行结果:
sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111

Map集合

(相当于python的字典)

Map 是一种无序的键值对的集合。

Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 “”。

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

定义如下:

/* 使用 make 函数 */
map_variable := make(map[KeyType]ValueType, initialCapacity)
其中 KeyType 是键的类型,ValueType 是值的类型,initialCapacity 是可选的参数,用于指定 Map 的初始容量。Map 的容量是指 Map 中可以保存的键值对的数量,当 Map 中的键值对数量达到容量时,Map 会自动扩容。如果不指定 initialCapacity,Go 语言会根据实际情况选择一个合适的值。

// 创建一个空的 Map
m := make(map[string]int)

// 创建一个初始容量为 10 的 Map
m := make(map[string]int, 10)

// 使用字面量创建 Map
m := map[string]int{
    "apple": 1,
    "banana": 2,
    "orange": 3,
}

// 获取键值对
v1 := m["apple"]
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值

// 修改键值对
m["apple"] = 5

// 获取 Map 的长度
len := len(m)

// 遍历 Map
for k, v := range m {
    fmt.Printf("key=%s, value=%d\n", k, v)
}

// 删除键值对
delete(m, "banana")