Golang

Golang

Go Hello World 实例

package main

import "fmt" 

func main() {
   /* 这是我的第一个简单的程序 */
   fmt.Println("Hello, World!")
}

Go 语言的空格

Go语言中变量的声明必须使用空格隔开, 如:

var age int;

格式化字符串

Go语言中使用fmt.Sprintf格式化字符串并赋值给新串:

package main

import(
    "fmt"
)

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

输出结果为:
	Code=123&endDate=2020-12-31

Go 语言数据类型

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

数字类型

序号类型描述
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)

浮点型

序号类型描述
1float32IEEE-754 32位浮点型数
2float64IEEE-754 64位浮点型数
3complex6432位实数和虚数
4complex12864位实数和虚数

其他数字类型

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

Go语言变量

变量可以通过变量名访问.

Go语言变量名由字母、数字、下划线组成, 其中首个字符不能为数字.

var identifier type

var identifier1 type, identifier2 type

例如:
package main
import "fmt"
func main(){
    var a = string ="Runoob"
    fmt.Println(a)
    
    var b,c int = 1, 2
    fmt.Println(b, c)
}

变量声明

第一种,指定变量类型,如果没有初始化,则变量默认为零值

package main
import "fmt"
func main() {

    // 声明一个变量并初始化
    var a = "RUNOOB"
    fmt.Println(a)

    // 没有初始化就为零值
    var b int
    fmt.Println(b)

    // bool 零值为 false
    var c bool
    fmt.Println(c)
}

以上实例执行结果为:
RUNOOB
0
false
  • 数值类型 (包括complex64/128) 为0

  • 布尔类型为false

  • 字符串为"" (空字符串)

以下几种类型为nil:
var a *int
var a []int
var a map[string] int
var a chan int
var a func(string) int
var a error // error 是接口

实例:
package main

import "fmt"

func main(){
   	var i int
    var f float64
    var b bool
    var s string
    fmt.s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

输出结果是:
0 0 false ""

第二种, 根据值自行判定

package main
import "fmt"
func main(){
   var d = true
   fmt.Println(d)
}
输出结果是:
true

第三种, 省略var, 注意 := 左侧如果没有声明新的变量, 就产生编译错误, 格式:

v_name := value
例如:
var intVal int
intVal := 1//此时不会产生编译错误, 因为有声明新的变量, 因为 := 是一个声明语句

intVal := 1 相等于:
var intVal int
intVal = 1

可以将var f string = "Runoob"简历 f := "Runoob":

实例:
package main

import "fmt"

func main(){
    f := "Runoob" //var f string = "Runoob"
    
    fmt.Println(f)
}

输出结果是:
Runoob

多变量声明

//类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3

var vname1, vname2, vname3 = v1, v2, v3 //和python 很像,不需要显示声明类型, 自动推断

vname1, vname2, vname3 := v1, v2, v3 //出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误

//这种因式分解关键字的写法一般用于声明全局变量
var{
    vname1 v_type1
    vname2 v_type2
}
实例:
package main

var x, y int
var ( // 这种因式分解关键字的写法一般用于声明全局变量
    a int
    b bool
)

var v, d int = 1, 2
var e, f = 123, "hello"

//这种不带声明格式的只能在函数体中出现
//g, h := 123, "hello"

func main(){
    g, h := 123, "hello"
    pringtln(x, y, a, b, c, d, e, f, g, h)
}
以上实例执行结果为:
0 0 0 false 1 2 123 hello 123 hello

值类型和引用类型

所有像int、float、bool和string这些基本类型都属于值类型, 使用这些类型的变量直接指向存在内存中的值:

在这里插入图片描述

当使用等号 = 将一个变量的值赋值给另一个变量时, 如: j = i , 实际上是在内存中将 i 的值进行了拷贝 :

在这里插入图片描述

  • 通过&i 来获取变量 i 的内存地址, 例如: 0xf840000040 (每次的地址都可能不一样) . 值类型的变量的值存储在栈中.
  • 内存地址会根据机器的不同而有所不同, 甚至相同的程序在不同的及其上执行后也会有不同的内存地址. 因为每台机器可能有不同的存储器布局, 并且位置分配也可能不同.
  • 更复杂的数据通常会需要使用多个字, 这些数据一般使用引用类型保存.
  • 一个引用类型的变量r1存储的是r1的值所在的内存地址(数字), 或内存地址中第一个字所在的位置.这个内存地址称之为指针, 这个指针实际上也被存在另外的某一个值中.
  • <font color=""同一个引用类型的指针指向的多个字可以是在连续的内存地址中 (内存布局是连续的) , 这也是计算效率最高的一种存储形式; 也可以将这写字分散存放在内存中, 每个字都指示了下一个字所在的内存地址.
  • 当使用赋值语句 r2 = r1 时, 只有引用 (地址) 被复制.
  • 如果r1的值被改变了, 那么这个值的所有引用都会指向被修改后的内容, 在这个例子中, r2也会受到影响.

使用 :=赋值操作符

  • 变量的初始化时省略变量的类型而由系统自动推断, 声明语句写上var关键字其实是显得有些多余了, 因此我们可以将它们简写为 a := 50 或 b := false.

  • a和b的类型 (int 和 bool) 将由编译器自动推断.

  • 这是使用变量的首选形式, 但是它只能被用在函数体内, 而不可以用于全局变量的声明与赋值. 使用操作符 := 可以高效地创建一个新的变量, 称之为初始化声明.

注意事项

如果在相同的代码块中, 我们不可以再次对于相同名称的变量使用初始化声明, 例如: a :=20 就是不被允许的, 编译器会提示错误 no new variables on left side of :=, 但是 a = 20 是可以的, 因为这是给相同的变量赋予一个新的值.

如果你在定义变量a 之前使用它, 则会得到编译错误 undefined: a .

如果你声明了一个局部变量却没有在相同的代码块中使用它, 同样会得到编译错误.

package main

import "fmt"

func main(){
    var a string = "abc"
    fmt.Println("hello, world")
}

尝试编译这段代码将得到的错误 a declared and not used.

此外, 单纯地给a 赋值也是不够的, 这个值必须被使用, 所以使用

fmt.Println("hello, world", a)

会移除错误.

但是全局变量是允许声明但不使用的. 同一类型的多个变量可以声明在同一行, 如:

var a, b, c int	

多变量可以在同一行进行赋值, 如:

var a, b int
var c string
a, b, c = 5, 7, "abc"

上面这行假设了变量a, b和c 都已经被声明, 否则的话应该这样使用:

a, b, c := 5, 7, "abc"

右边的这些值以相同的顺序赋值给左边的变量, 所以a的值是5, b的值是7, c的值是"abc".

这被称为并行或同时赋值.

如果你想要交换两个变量的值, 则可以简单地使用a, b = b, a , 两个变量的类型必须是相同.

空白标识符 _ 也被用于抛弃值, 如值 5 在 _ , b := 5, 7中被抛弃.

_实际上是一个只写变量, 你不能得到它的值. 这样做是因为 Go语言中你必须使用所有被声明的变量, 但有时你并不需要使用从一个函数得到的所有返回值.

并行赋值也被用于当一个函数返回多个返回值时, 比如这里的 val和错误 err是通过调用 Func1 函数同时得到 : val, err = Func1(var1).

package main

import "fmt"

func main(){
    _,numb,strs := numbers() //只获取函数返回值的后两个
    fmt.Println(numb,strs)
}

//一个可以返回多个值的函数
func numbers()(int,int,string){
    a , b , c , := 1 , 2 , "str"
    return a,b,c
}

输出结果:
2 str

Go语言常量

常量的定义格式:

const identifier [type] = value

可以省略类型说明符[type], 因为编译器可以根据变量的值来推断其类型.

  • 显式类型定义: const b string = “abc”

  • 隐式类型定义: const b = “abc”

多个相同类型的声明可以简写为:

const c_name1, c_name2 = value1, value2
package main

import "fmt"

func main(){
    const LENGTH int = 10
    const WIDTH int =5
    var area int
    const a, b, c = 1, false, "str" //多重赋值
    
    area = LENGTH * WIDTH
    fmt.Printf("面积为 : %d", area)
    println()
    println(a, b, c)
}

以上实例运行结果为:
面积为	: 50
1 false str

常量还可以用作枚举:

const (
	Unknown = 0
	Female = 1
	Male = 2
)

数字0、1和2分别代表未知性别、女性和男性.

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值. 常量表达式中, 函数必须是内置函数, 否则编译不过:

package main

import "unsafe"
const(
	a = "abc"
    b = len(a)
    c = unsafe.Sizeof(a)
)

func main(){
    println(a, b, c)
}

以上实例运行结果为:
abc 3 16

iota

iota, 特殊常量, 可以认为是一个可以被编译器修改的常量.

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

iota 可以被用作枚举值 :

const (
	a = iota
    b = iota
    c = iota
)

第一个 iota 等于0, 每当iota在新的一行被使用时, 它的值都会自动加1; 所以a=0,
 b=1, c=2可以简写为如下形式:
const(
	a = iota
	b
    c
)

iota用法

package

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

实例
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
j= 24

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

简单表诉 :

  • i=1 : 左移1位, 变为二进制 110, 即 6;

  • k=3: 左移2位, 变为二进制 1100, 即 12;

  • l=3: 左移3位, 变为二进制11000, 即24.

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

Go 语言运算符

算术运算符

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

关系运算符

下表列出了所有Go语言的关系运算符。假定 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

逻辑运算符

下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False。

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

位运算符

位运算符对整数在内存中的二进制位进行操作.

下表列出了位运算符 &, |, 和 ^ 的计算 :

pqp & qp | qp ^ q
00000
01011
11110
10011
假定 A = 60; B = 13; 其二进制数转换为:

A = 0011 1100

B = 0000 1101

---------------

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

Go语言支持的位运算符如下表所示. 假定A为60, B为13:

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

import "fmt"

func main(){
    
    var a uint = 60		/* 60 = 0011 1100 */
    var v uint = 13		/* 13 = 0000 1101 */
    var c uint = 0
    
    c = a & b			/* 12 = 0000 1100 */
    fmt.Printf("第一行 - c 的值为 %d\n", c)
    
    c = a | b			/* 61 = 0011 1101 */
    fmt.Printf("第二行 - c 的值为 %d\n", c )		
    
    c = a ^ b 			/* 49 = 0011 0001 */
    fmt.Printf("第三行 - c 的值为 %d\n", c)
    
    c = a << 2     /* 240 = 1111 0000 */
   	fmt.Printf("第四行 - c 的值为 %d\n", c )

   	c = a >> 2     /* 15 = 0000 1111 */
   	fmt.Printf("第五行 - c 的值为 %d\n", c )
}

以上实例运行结果:
第一行 - c 的值为 12
第二行 - c 的值为 61
第三行 - c 的值为 49
第四行 - c 的值为 240
第五行 - c 的值为 15

赋值运算符

下表列出了所有Go语言的赋值运算符.

运算符描述实例
=简单的赋值运算符,将一个表达式的值赋给一个左值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

其他运算符

下表列出了Go语言的其他运算符。

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

import "fmt"

func main(){
    var a int = 4
    var b int32
    var c float32
    var ptr *int
    
    /* & 和 * 运算符实例 */
    ptr = &a /* 'ptr' 包含了 'a' 变量的地址 */
    fmt.Printf("a 的值为 %d\n", a);
    fmt.Printf("*ptr 为 %d\n", *ptr);
}

以上实例运行结果:1- a 变量类型为 = int2- b 变量类型为 = int323- c 变量类型为 = float32
a 的值为 4
*ptr 为 4 

运算符优先级

有些运算符拥有较高的优先级, 二元运算符的运算方向均是从左至右. 下表列出了所有运算符以及它们的优先级, 由上至下代表优先级由高到低 :

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

当然, 你可以通过使用括号来临时提升某个表达式的整体运算优先级.

package main

import "fmt"

func main(){
	var a int = 20
	var b int = 10
	var c int = 15
	var d int = 5
	var e int;
	
	e = (a + b) * c / d;	// (30 * 15) / 5
	fmt.Printf("(a + b) * c / d 的值为 : %d\n", e);
	
	e = ((a + b) * c) / d;  // (30 * 15) / 5 
	fmt.Printf("((a + b) * c) / d 的值为	: %d\n" , e);
	
	e = (a + b) * (c / d);	// (30) * (15/5)
	fmt.Printf("(a + b) * (c / d) 的值为	: %d\n", e);
	
	e = a + (b * c) / d;	// 20 +(150/5)
	fmt.Printf("a + (b * c) / d 的值为  : %d\n" ,  e );  
}

以上实例运行结果:
(a + b) * c / d 的值为 : 90
((a + b) * c) / d 的值为  : 90
(a + b) * (c / d) 的值为  : 90
a + (b * c) / d 的值为  : 50

Go 语言条件语句

Go 语言提供了以下几种条件判断语句:

语句描述
if 语句if 语句 由一个布尔表达式后紧跟一个或多个语句组成。
if…else 语句if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
if 嵌套语句你可以在 ifelse if 语句中嵌入一个或多个 ifelse if 语句。
switch 语句switch 语句用于基于不同条件执行不同动作。
select 语句select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

注意:Go 没有三目运算符,所以不支持 ?: 形式的条件判断。

语法
Go 编程语言中 if 语句的语法如下:

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

语法
Go 编程语言中 if...else 语句的语法如下:

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

语法
Go 编程语言中 if...else 语句的语法如下:

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

语法
Go 编程语言中 switch 语句的语法如下:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

语法
Go 编程语言中 select 语句的语法如下:

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

Go语言循环语句

语法
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

和 C 语言的fot一样;
for init; condition; post { }

和 C 的 while 一样;
for condition { }

和 C 的for(;;) 一样;
for { }
  • init: 一般为赋值表达式, 给控制变量赋初值 ;
  • condition: 关系表达式或逻辑表达式, 循环控制条件
  • post : 一般为赋值表达式, 给控制变量增量或减量.

for循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环. 格式如下:

for key, value := range oldMap{
	newMap[key] = value
}
实例
计算 110 的数字之和:

package main

import "fmt"

func main(){
    sum := 0
    for i := 0; i <= 10; i++ {
        sum += i
    } 
    fmt.Println(sum)
}

输出结果为:
55

init 和 post 参数是可选的,我们可以直接省略它,类似 While 语句。

以下实例在 sum 小于 10 的时候计算 sum 自相加后的值:

package main

import	"fmt"

func main(){
    sum := 1
    for ; sum <=10; {
        sum += sum
    }
    fmt.Println(sum)
    
    //这样写也可以, 更像while语句形式
    for sum <= 10{
        	sum += sum
    }
    fmt.println(sum)
}

输出结果为:
16
16

无限循环:

package main

import "fmt"

func main() {
        sum := 0
        for {
            sum++ // 无限循环下去
        }
        fmt.Println(sum) // 无法输出
}

要停止无限循环,可以在命令窗口按下ctrl-c

For-each range 循环

这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。

package main
import "fmt"

func main() {
    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 的值 = %d\n", i,x)
    } 
}

以上实例运行输出结果为:
0 google
1 runoob
第 0 位 x 的值 = 11 位 x 的值 = 22 位 x 的值 = 33 位 x 的值 = 54 位 x 的值 = 05 位 x 的值 = 0

循环控制语句

GO语言支持以下几种循环控制语句 :

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

实例
package main

import "fmt"

func main(){
    /* 定义局部变量 */
    var a int = 10
    
    /* 循环 */
    LOOP: for a < 20 {
        if a == 15 {
            /* 跳过迭代 */
            a = a + 1
            goto LOOP
        }
         fmt.Printf("a的值为 : %d\n", a)
      	 a++ 
    }
}

以上实例执行结果为:
a的值为 : 10
a的值为 : 11
a的值为 : 12
a的值为 : 13
a的值为 : 14
a的值为 : 16
a的值为 : 17
a的值为 : 18
a的值为 : 19

Go语言函数

函数定义

Go 语言函数定义格式如下:

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 {
    /* 声明局部变量 */
    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
}

以上实例在 main() 函数中调用 max()函数,执行结果为:
最大值是: 200

函数返回多个值

Go 函数可以返回多个值, 例如 :

package main

import "fmt"

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

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

以上实例执行结果为 : 
Runoob Google

函数参数

  • 值传递
    • 值传递是指在调用函数时将实际参数复制一份传递到函数中, 这样在函数中如果对参数进行修改, 将不会影响到实际参数.
/* 定义相互交换值的函数 */
func swap(x, y int) int {
   var temp int

   temp = x /* 保存 x 的值 */
   x = y    /* 将 y 值赋给 x */
   y = temp /* 将 temp 值赋给 y*/

   return temp;
}
  • 引用传递
    • 引用传递是指在调用函数时将实际参数的地址传递到函数中, 那么在函数中对参数所进行的修改, 将影响到实际参数.
/* 定义交换值函数*/
func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保持 x 地址上的值 */
   *x = *y      /* 将 y 值赋给 x */
   *y = temp    /* 将 temp 值赋给 y */
}

函数用法

Go 语言函数作为实参
package mainn

import (
	"fmt"
    "math"
)

func main(){
    /* 声明函数变量 */
    getSquareRoot := func(x float64) float64 {
        return math.sqrt(x)
    }
    /* 使用函数 */
    fmt.Println(getSquareRoot(9))
}

以上代码执行结果为:
3
Go 语言函数闭包
package main

import "fmt"

func getSequence() func() int {
    i := 0
    return func() int {
        i += 1
        return i
    }
}

func main(){
    /* nextNumber 为一个函数, 函数i 为0 */
    nextNumber := getSequence()
    
    /* 调用 nextNumber 函数, i变量自增 1 并返回 */
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    
    /* 创建新的函数 nextNumber1, 并查看结果 */
    nextNumber1 := getSequence()
    fmt.Println(nextNumber1())
    fmt.Println(nextNumber1())
}
以上代码执行结果为:
1
2
3
1
2
Go 语言函数方法
func (variable_name variable_data_type) function_name() [return_type]{
    /* 函数体 */
}

package main

import (
	"fmt"
)

/* 定义结构体 */
type Circle struct {
    radius float64
}

func main() {
    var c1 Circle
    c1.radius = 10.00
    fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
    //c.radius 即为 Circle 类型对象中的属性
    return 3.14 * c.radius * c.radius
}

以上代码执行结果为:
圆的面积 = 314

GO 语言变量作用

Go 语言中变量可以在三个地方声明 :

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

局部变量

在函数体内声明的变量称之为局部变量, 它们的作用域只在函数体内, 参数和返回值变量也是局部变量.

package main

import "fmt"

func main() {
    /* 声明局部变量 */
	var a, b, c int
    
    /* 初始化参数 */
    a = 10
    b = 20
    c = a + b
    
    fmt.Printf("结果: a = %d, b = %d and c = %d\n", a, b, c)
}

以上实例执行输出结果为:
结果: a = 10, b = 20 and c = 30

全局变量

在函数体外声明的变量称之为全局变量, 全局变量可以在整个包甚至外部包 (被导出后) 使用.

package main

import "fmt"

func main() {
    /* 声明局部变量 */
    var a, b int
    
    /* 初始化参数 */
    a = 10
    b = 20
    g = a + b
    
    fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)
}
以上实例执行输出结果为 :
结果: a = 10, b = 20 and g = 30

Go语言程序中全局变量与局部变量名称可以相同, 但是函数内的局部变量会被优先考虑

package main

import "fmt"

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

func main() {
    /* 声明局部变量 */
    var g int = 10
    fmt.Printf ("结果: g = %d\n", g)
}
以上实例执行输出结果为:
结果: g = 10

形式参数

形式参数会作为函数的局部变量来使用

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 = 3

初始化局部和全局变量

不同类型的局部和全局变量默认值为:

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

Go 语言数组

声明数组

语法格式如下:
var variable_name [SIZE] variable_type

例如:
var balance [10] float32

初始化数组

var balance = [5]float32{1000.0, 2.0, 3.4, 7,0, 50.0}

balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果数组长度不确定, 可以使用 ... 代替数组的长度, 编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
	balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果设置了数组的长度, 我们还可以指定下标来初始化元素:
//	将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0, 3:7.0}

初始化数组中{} 中的元素个数不能大于[] 中的数字.
如果忽略 [] 中的数字不设置数组大小, Go语言会根据元素的个数来设置数组的大小:

balance[4] = 50.0

以上实例读取了第五个元素. 数组元素可以通过索引 (位置) 来读取 (或者修改), 索引从0开始, 第一个元素索引为0, 第二个索引为1, 以此类推.

在这里插入图片描述

访问数组元素

数组元素可以通过索引(位置)来读取. 格式为数组名后加中括号, 中括号为索引的值.

var salary float32 = balance[9]

package main 

import "fmt"

func main(){
    var n [10]int /* n 是一个长度为10 的数组 */
    var i,j int
    
    /* 为数组 n 初始化元素 */
    for i = 0; i < 10; i++{
       n[i] = i + 100 /* 设置元素为 i + 100 */
    }
    
    /* 输出每个数组元素的值 */
    for j = 0; j < 10; j++ {
        fmt.Printf("Element[%d] = %d\n", j, n[j])
    }
}

以上实例执行结果如下:

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

Go 语言向函数传递数组

形参设定数组大小:
void myFunction(param [10]int)
{	}

形参未设定数组大小:
void myFunction(param []int)
{	}
package main

import "fmt"

func main() {
    /* 数组长度为5 */
    var balance = [5]int {1000, 2, 3, 17, 50}
    var avg float32
    
   /* 数组作为参数传递给函数 */
    avg = getAverage( balance, 5);
    
    /* 输出返回的平均值 */
    fmt.Printf("平均值为: %f", avg);
}

func getAverage(arr [5]int, size int) float32 {
    var i, sum int
    var avg float32
    
    for i = 0; i < size; i++ {
        sum += arr[i]
    }
    
    avg = float32(sum) / float32(size)
    
    return avg;
}

以上实例执行输出结果为:
平均值为: 214.399994

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 变量储存的指针地址: %\n", ip)
    
    /* 使用指针访问值 */
    fmt.Printf(" *ip 变量的值: %d\n", *ip)
}

以上实例执行输出结果为:
a 变量的地址是: 20818a220
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20

Go空指针

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

Go指针更多内容

Go指针数组
整型指针数组:
var ptr [MAX]*int

ptr 为整型指针数组. 因此每个元素都指向了一个值.
package main

import "fmt"

const MAX int = 3

func main(){
    a := []int{10,100,200}
    var i int
    var ptr [MAX]*int;
    
    for i = 0; i < MAX; i++ {
        ptr[i] = &a[i] /* 整数地址赋值给指针数组 */
    }
    
    for i = 0; i < MAX; i++ {
        fmt.Printf("a[%d] = %d\n", i,*ptr[i])
    }
}

以上代码执行输出结果为:
a[0] = 10
a[1] = 100
a[2] = 200
Go 语言指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址, 则称这个指针变量为指向指针的指针变量.

当定义一个指向指针的指针变量时, 第一个指针存放第二个指针的地址, 第二个指针存放变量的地址:

在这里插入图片描述

指针变量声明格式如下:
var ptr **int;

package main

import "fmt"

func main() {
   	var a int 
    var ptr *int
    var pptr **int

    a = 3000
   
    /* 指针 ptr 地址 */
    ptr = &a
    
    /* 指向指针 ptr 地址 */
    pptr = &ptr
    
    /* 获取 pptr 的值 */
    fmt.Printf("变量 a = %d\n", a)
    fmt.Printf("指针变量 *ptr = %d\n", *ptr )
    fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}

以上实例执行输出结果为:
变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000
Go 语言指针作为函数参数

Go语言允许向函数传递指针, 只需要在函数定义的参数上设置为指针类型即可.

package main

import "fmt"

func main() {
    /* 定义局部变量 */
    var a int = 100
    var b int = 200
    
    fmt.Printf("交换前 a 的值: %d\n", a)
    fmt.Printf("交换前 b 的值: %d\n", b)
    
    /* 调用函数用于交换值
    	&a 指向 a 变量的地址
    	&b 指向 b 变量的地址
    */
    swap(&a, &b)
    
   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}

func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保存 x 地址的值 */
   *x = *y      /* 将 y 赋值给 x */
   *y = temp    /* 将 temp 赋值给 y */
}

以上实例允许输出结果为:
交换前 a 的值 : 100
交换前 b 的值 : 200
交换后 a 的值 : 200
交换后 b 的值 : 100

Go 语言结构体

结构体定义需要使用 type 和 struct 语句. struct 语句定义一个新的数据类型, 结构体中有一个或多个成员. type语句设定了结构体的名称.

结构体的的格式如下:
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 语言", "www.runoob.com", "Go 语言教程", 6495407})

    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})

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

输出结果为:
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com Go 语言教程 6495407}
{Go 语言 www.runoob.com  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 = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 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 : www.runoob.com
Book 1 subject : Go 语言教程
Book 1 book_id : 6495407
Book 2 title : Python 教程
Book 2 author : www.runoob.com
Book 2 subject : Python 语言教程
Book 2 book_id : 6495700

结构体作为函数参数

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 = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 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 : www.runoob.com
Book subject : Go 语言教程
Book book_id : 6495407
Book title : Python 教程
Book author : www.runoob.com
Book subject : Python 语言教程
Book book_id : 6495700

结构体指针

定义指向结构体的指针类似于其他指针变量, 格式如下:
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 = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 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 : www.runoob.com
Book subject : Go 语言教程
Book book_id : 6495407
Book title : Python 教程
Book author : www.runoob.com
Book subject : Python 语言教程
Book book_id : 6495700

Go 语言切片(Slice)

Go 语言切片是对数组的抽象.

Go数组的长度不可改变, 在特定场景中这样的集合就不太适用, Go中提供了一种灵活, 功能强悍的内置类型切片(“动态数组”), 与数组相比切片的长度是不固定的, 可以追加元素,在追加时可能使切片的容量增大.

定义切片

你可以声明一个未指定大小的数组来定义切片:
var identifier []type

切片不需要说明长度.或使用make()函数来创建切片:
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的最后一个元素.

s1 := 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)
    
    prinSlice(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(numbes == nil){
        fmt.Printf("切片是空的")
    }
}

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

以上实例运行输出结果为:
len=0 cap=0 slice=[]
切片是空的

切片截取

可以通过设置下限及上限来设置截取切片[lower-bound:upper-bound], 实例如下:

package main

import "fmt"

func main(){
    /* 创建切片 */
    numbers := []int{0,1,2,3,4,5,6,7,8}
    printSlice(numbers)
    
    /* 打印原始切片 */
    fmt.Println("number ==", numbers)
    
    /* 打印子切片从索引1(包含) 到索引4(不包含) */
    fmt.Println("number[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(不包含) */
    numbers2 := numbers[:2]
    printSlice(number2)
    
    /* 打印子切片从索引 0(包含) 到索引 5(不包含) */
    numbers3 := numbers[2:5]
    printSlice(nubmer3)
}

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() 函数

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来.

下面的代码描述了从拷贝切片的copy方法和向切片追加新元素的append方法.

package main

import "fmt"

func main(){
    var numbers []int
    printSlice(numbers)
    
    /* 允许追加空切片 */
    numbers = append(numbers, 0)
    printSlice(numbers)
    
    /* 向切片添加一个元素 */
    numbers = append(numbers, 1)
    printSlice(numebrs)
    
    /* 同时添加多个元素 */
    numbers = append(numbers, 2,3,4)
    printlSlice(numebrs)
    
    /* 创建切片 unmbers1 是之前切片的两倍容量 */
    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)
}

以上代码执行输出结果为:
len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]

Go语言范围(Range)

Go语言中range 关键字用于for循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素. 在数组和切片中它返回元素的索引和索引对应的值, 在集合中返回key-value对.

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将传入index和值两个变量, 上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了. 有时候我们确实需要知道它的索引.
    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

Go 语言Map(集合)

Map是一种集合, 所以我们可以像迭代数组和切片那样迭代它. 不过,Map是无序的, 我们无法决定它的返回顺序, 这是因为Map是使用hash表来实现的.

定义Map
可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
/* 声明变量,默认map是nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

如果不初始化map, 那么就会创建一个nil map. nil map不能用来存放键值对

实例:
package main

import "fmt"

func main() {
    var countryCapitalMap map[String]string /* 创建集合 */
    countryCapitaMap = make(map[string]string)
    
    /* map插入key - value对, 各个国家对应的首都 */
    countryCapitalMap ["France"] = "巴黎"
    countryCapitalMap ["Italy"] = "罗马"
    countryCapitalMap ["Japan"] = "东京"
    countryCapitalMap ["India"] = "新德里"

	/* 使用键输出地图值 */
    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap [country])
    }
    
    /* 查看元素在集合中是否存在 */
    capital, ok := countryCapitalMap ["American"] 
     if (ok) {
        fmt.Println("American 的首都是", capital)
    } else {
        fmt.Println("American 的首都不存在")
    }
}

以上实例运行结果为:
France 首都是 巴黎
Italy 首都是 罗马
Japan 首都是 东京
India  首都是 新德里
American 的首都不存在

delete()函数

delete()函数用于删除集合的元素, 参数为map 和其对应的key. 实例如下:

package main

import "fmt"

func main() {
    /* 创建map */
    countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Room", "Japan": "Tokyo", "India"; "New delhi"}
    
    fmt.Println("原始地图")
    
    /* 打印地图 */
    for country := range countryCapitalMap {
        fmt.Println(country,"首都是", countryCapitalMap [country])
    }
      /*删除元素*/ delete(countryCapitalMap, "France")
        fmt.Println("法国条目被删除")

        fmt.Println("删除元素后地图")

        /*打印地图*/
        for country := range countryCapitalMap {
                fmt.Println(country, "首都是", countryCapitalMap [ country ])
        }
}

以上实例运行结果为:
原始地图
India 首都是 New delhi
France 首都是 Paris
Italy 首都是 Rome
Japan 首都是 Tokyo
法国条目被删除
删除元素后地图
Italy 首都是 Rome
Japan 首都是 Tokyo
India 首都是 New delhi

Go语言递归函数

递归, 就是在运行的过程中调用自己.

func recursion() {
    recursion() /* 函数调用自身 */
}

func main() {
    recursion()
}

Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。

递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等。

阶乘
package main

import "fmt"

func Factorial(n uint64)(result uint64){
    if(n > 0){
        result = n * Factorial(n-1)
        return result
    }
    return 1
}

func main(){
    var i int = 15
    fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

以上实例执行输出结果为:
15` 的阶乘是 1307674368000

Go 语言类型转换

类型转换用于将一种数据类型的变量转换为另一种类型的变量. Go语言类型转换基本格式如下:

type_name(expression)
type_name 为类型,expression 为表达式。

实例:
以下实例中将整型转化为浮点型,并计算结果,将结果赋值给浮点型变量:
package main

import "fmt"

func main(){
    var sum int = 17
    var count int = 5
    var mean float32
    
    mean = float32(sum)/float32(count)
    fmt.Printf("mean 的值为: %f\n", mean)
}
以上实例执行输出结果为:
mean 的值为: 3.400000

country := range countryCapitalMap {
fmt.Println(country, “首都是”, countryCapitalMap [country])
}

/* 查看元素在集合中是否存在 */
capital, ok := countryCapitalMap ["American"] 
 if (ok) {
    fmt.Println("American 的首都是", capital)
} else {
    fmt.Println("American 的首都不存在")
}

}

以上实例运行结果为:
France 首都是 巴黎
Italy 首都是 罗马
Japan 首都是 东京
India 首都是 新德里
American 的首都不存在


delete()函数

delete()函数用于删除集合的元素, 参数为map 和其对应的key. 实例如下:

```go
package main

import "fmt"

func main() {
    /* 创建map */
    countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Room", "Japan": "Tokyo", "India"; "New delhi"}
    
    fmt.Println("原始地图")
    
    /* 打印地图 */
    for country := range countryCapitalMap {
        fmt.Println(country,"首都是", countryCapitalMap [country])
    }
      /*删除元素*/ delete(countryCapitalMap, "France")
        fmt.Println("法国条目被删除")

        fmt.Println("删除元素后地图")

        /*打印地图*/
        for country := range countryCapitalMap {
                fmt.Println(country, "首都是", countryCapitalMap [ country ])
        }
}

以上实例运行结果为:
原始地图
India 首都是 New delhi
France 首都是 Paris
Italy 首都是 Rome
Japan 首都是 Tokyo
法国条目被删除
删除元素后地图
Italy 首都是 Rome
Japan 首都是 Tokyo
India 首都是 New delhi

Go语言递归函数

递归, 就是在运行的过程中调用自己.

func recursion() {
    recursion() /* 函数调用自身 */
}

func main() {
    recursion()
}

Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。

递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等。

阶乘
package main

import "fmt"

func Factorial(n uint64)(result uint64){
    if(n > 0){
        result = n * Factorial(n-1)
        return result
    }
    return 1
}

func main(){
    var i int = 15
    fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

以上实例执行输出结果为:
15` 的阶乘是 1307674368000

Go 语言类型转换

类型转换用于将一种数据类型的变量转换为另一种类型的变量. Go语言类型转换基本格式如下:

type_name(expression)
type_name 为类型,expression 为表达式。

实例:
以下实例中将整型转化为浮点型,并计算结果,将结果赋值给浮点型变量:
package main

import "fmt"

func main(){
    var sum int = 17
    var count int = 5
    var mean float32
    
    mean = float32(sum)/float32(count)
    fmt.Printf("mean 的值为: %f\n", mean)
}
以上实例执行输出结果为:
mean 的值为: 3.400000
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值