go语言

安装篇

Mac安装go语言

下载地址:https://golang.google.cn/dl/

配置环境变量:

vim /etc/profile
export GOROOT=/usr/local/go
export GO111MODULE=on
export GOPATH=/Users/fangxing/go
export GOPROXY=https://goproxy.cn,direct
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
  • GOOOT是go的安装目录,go原生的工具在该目录下
  • GOPATH通常存放自建开发的代码或者第三方依赖库
  • GO111MODULE=on go会忽略GOPATH和vendor文件夹,只根据go.mod下载依赖。从go1.16开始其指默认为on
  • GOPROXY: 下载依赖库时走哪个镜像代理,可以在公司内部自建镜像
  • PATH下的二进制文件可以在任意目录下直接运行
  • 在$GOPATH目录建3个子目录: src、bin、pkg

GO Modules依赖包查找机制

  • 下载的第三方依赖存储在$GOPATH/pkg/mod下
  • go install生成的可执行文件存储在$GOPATH/bin下
  • 依赖包的查找顺序
    • 工作目录
    • $GOPATH/pkg/mod
    • $GOROOT/src

安装vscode软件

下载地址:https://code.visualstudio.com/Download

安装插件 go、Code Runner

快速生成代码片段

pkgm   main包+main主函数
ff     fmt.Printf("", var)
for    for i :=0; i < count; i== {}
forr   for _, v := ranage v {}
fmain   func main() {}
a.print!  fmt.Printf("a: %v\n", a)

go包地址:https://pkg.go.dev/

打印hello go

package main

import "fmt"

func main() {
	fmt.Println("hello go")
}

go常用命令

  • go help: 查看帮助文档

    go help build
    
  • go build: 对源代码和依赖的文件进行打包,生成可执行文件

    # go build main.go
    # ls
    main    main.go
    #  ./main 
    hello go
    
    # go build -o my_go main.go
    # ./my_go
    
  • go install: 编译并安装包和依赖,安装在$GOPATH/bin下

    • go install github/tinylib/msgp@latest 会在$GOPATH/bin下生成msgp可执行文件
    go install day01/hello.go
    
  • go get: 把依赖库添加到当前module中,如果本机之前从未下载过则先下载

    • go get github/tinylib/msgp会在$GOPATH/pkg/mod目录下生成github/tinylib/msgp目录
    # go mod init go_pro
    go: creating new go.mod: module go_pro
    go: to add module requirements and sums:
            go mod tidy
    #  go get github.com/go-sql-driver/mysql
    go: downloading github.com/go-sql-driver/mysql v1.7.0
    go: added github.com/go-sql-driver/mysql v1.7.0
    
  • go mod: mudule相关命令

    • go mod init module_name
    • go mode tidy 通过扫描当前项目中的所有代码来添加未被记录的依赖到go.mod文件或从go.mod文件中删除不再使用的依赖
  • go run:编译并运行程序

  • go test: 执行测试代码

  • go tool: 执行go自带的工具

    • go tool pprof 对cpu、内存和协程进行监控
    • go tool trace 跟踪协程的执行过程
  • go vet: 检查代码中的静态错误

  • go fmt: 对代码文件进行格式化,如果用了IDE这个命令就不需要了

    • go fmt day01/hello.go
  • go doc: 查看go标准库或第三方库的帮助文档

    • go doc fmt
    • go doc github.com/go-sql-driver/mysql
  • go version: 查看go版本号

  • go env: 查看go环境信息

参考文档:https://golang.org/doc/cmd

如何编写golang代码

代码组织

​ go应用使用包和模块来组织代码,包对应到文件系统的文件夹,模块就是.go的go源文件。一个包会有多个模块,或者多个子包

go项目管理工具

​ 早期的go项目使用gopath来管理项目,不方便而且容易出错,从golang1.11开始使用gomod管理项目,当然还有第三方模块例如govendor。

实现步骤

1.创建项目

​ 创建一个文件夹,用vscode打开。

2.初始化项目

打开vscode终端 执行:

go mod init go_pro

3.创建包

​ 创建user文件夹

4.创建模块

​ 创建user.go文件

package user

func Hello() string {
	return "hello"
}

5.相互调用

在项目目录下创建main.go文件

package main

import (
	"fmt"
	"go_pro/user"
)

func main() {
	s := user.Hello()
	fmt.Printf("s: %v\n", s)
}


# go run main.go 
s: hello

golang标识符、关键字、命名规则

标识符

标识符就是给变量、常量、函数、方法、结构体、数组、切片、接口起名字。

标识符的命名规则

1.标识符由数字、字母和下划线(_)组成。

2.只能以字母和下划线(_)开头。

3.标识符区分大小写。

举例说明标识符的命名

正确的命名
package main

import "fmt"

func main() {
  var name string
  var age int
  var _sys int
}
错误的标识符
package main

import "fmt"

func main() {
  var 1name string
  var &age int
  var !email
}

go语言关键字

go语言提供了25个关键字,如下所示:

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

除了以上介绍的关键字,go语言还有36个预定义标识符,其中包含了基本类型的名称和一些基本内置函数,见下表:

append bool byte cap close complex complex64 complex128 uint16
copy false float32 float64 imag int int8 int16 uint32
int32 int64 iota len make new nil panic uint64
print println real recover string true uint uint8 uintptr

go语言命名规范

go是一门区分大小写的语言

命名规则涉及变量、常量、全局函数、结构、接口、方法等命名。go语言从语法层面进行了以下限定:任何需要对外暴露的名字必须大写字母开头,不需要对外暴露的则以小写字母开头。

包名称

保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为小写单词,不要使用下划线或者混合大小写。

package dao
package service
文件命名

尽量采取有意义的文件名,简短,有意义,应该为小写单词,使用下划线分隔各个单词。

customer_dao.go
结构体命名

采用驼峰命名法,首字母根据访问控制大小写或者小写

struct 申明和初始化格式采用多行,例如下面:

type CutomerOrder struct {
  Name string
  Address string
}
order := CutomerOrder{"tom", "北京海淀"}
接口命名

命名规则基本和上面结构体类型一样

单个函数的结构名以”er“作为后缀,例如 Reader,Writer。

type Reader interface {
  Read(p []byte) (n int, err error)
}
变量命名

和结构体类似,变量名称一般遵循驼峰法,首字母根据访问原则大写或者小写,但遇到特有名词时,需要遵守以下规则:

如果变量为私有,且特有名词为首个单词,则使用小写,如appService若变量类型为bool类型,则名称以Has,Is,Can或者Allow开头

var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
常量命名

常量均需要全部大写字母组成,并使用下划线分词

const APP_URL = "http://www.baidu.com"

如果是枚举类型的常量,需要先创建相应的类型:

type Scheme string

const (
	HTTP Scheme = "http"
  HTTPS Scheme = "https"
)
错误处理

错误处理的原则就是不能丢弃任何有返回err的调用,不要使用_丢弃,必须全部处理。接受到错误,要么返回err,或者使用log记录下来尽早return: 一旦有错误发生,马上返回,尽量不要使用panic,除非你知道你在做什么,错误描述如果是英文必须为小写,不需要标点结尾,采用独立的错误流进行处理

//错误写法
if err != nil {
  //错误处理
}else {
  //正常代码
}

//正确写法
if err != nil {
  //错误处理
  return //或者继续
}
// 正常代码
单元测试

单元测试文件名命名规则为 example_test.go 测试用例

的函数名必须以Test开头,例如: TestExample每个重要的函数都要首先编写测试用例,测试用例和正规代码一起提交方便进行回归。

go语言变量

变量是计算机语言中能储存计算结果或能表示值的抽象概念。不同的变量保存的数据类型可能会不一样。

声明变量

go语言中的变量需要声明后才能使用,同一个作用域内不支持重复声明。并且go语言的变量声明后必须使用。

声明变量的语法

var identifier type

var: 声明变量关键字

Indentifier: 变量名称

type: 变量类型

例如:
package main

import "fmt"

func main() {
	var name string
  var age int
  var m bool
}
批量声明
package main

func main() {
  var (
  	name string
    age int
  	ok bool
  )
}
变量的初始化

go语言在声明变量的时候,会自动对变量的内存区域进行初始化操作。每个变量会被初始化成其类型的默认值,例如: 整型和浮点型变量的默认值为0。字符串变量的默认值为空字符串""。布尔值变量默认为false。切片、函数、指针变量默认为nil。

变量初始化语法
var 变量名 类型 = 表达式
例如
package main

func main() {
	var name string = "fangxing"
  var age int = 18
  var site string = "www.baidu.com"
}
类型推导
package main

func main() {
	var name = "fangxing"
	var age = 18
	var site = "www.baidu.com"
}
初始化多个变量
package main

func main() {
		var name, site, age = "fangxing", "www.baidu.com", 18
}
短变量声明

在函数内部,可以使用 :=运算符对变量进行声明和初始化

package main

func main() {
  name := "fangxing"
  site := "www.baidu.com"
  age := 20
}
匿名变量

如果我们接收到多个变量,有一些变量使用不到,可以使用下划线_表示变量名称,这个变量叫做匿名变量。例如:

package main

import "fmt"

func getNameAndAge() (string, int){
  return "fangxing", 18
}

func main() {
  name, _ := getNameAndAge()
  fmt.Printf("name: %v\n", name)
}

go语言常量

常量,就是在程序编译阶段就确定下来的值,而程序在运行时则无法改变该值。在go程序中,常量可以是数值类型(包括整型、浮点型和复数类型)、布尔类型、字符串类型等。

定义常量的语法

定义一个常量使用const关键字,语法格式如下:

const constanName [type] = value

const: 定义常量关键字

constanName: 常量名称

type: 常量类型

value: 常量的值

实例:
package main

func main() {
	const PI float64 = 3.14
	//可省略类型
	const PI2 = 3.1415

	// 批量赋值
	const (
		width  = 100
		height = 200
	)

	//多重赋值
	const i, j = 1, 2
	const a, b, c = 1, 2, "foo"
}

const 同时声明多个变量时,可以省略了值表示和上面一行的值相同
package main

import "fmt"

func main() {
	const (
		a1 = 100
		a2
		a3
	)
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a2: %v\n", a2)
	fmt.Printf("a3: %v\n", a3)
}

// 运行结果
a1: 100
a2: 100
a3: 100

iota

iota比较特殊,可以被认为是一个可被编辑器修改的常量,它默认开始值是0,每调用一次加1,遇到const关键字时被重置为0。

实例:
package main

import "fmt"

func main() {
	const (
		a1 = iota
		a2 = iota
		a3 = iota
	)
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a2: %v\n", a2)
	fmt.Printf("a3: %v\n", a3)
}

//运行结果
a1: 0
a2: 1
a3: 2
使用_跳过某些值
package main

import (
	"fmt"
)

func main() {
	const (
		a1 = iota
		_
		a3 = iota
	)
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a3: %v\n", a3)
}

//运行结果
a1: 0
a3: 2
iota声明中间插队
package main

import (
	"fmt"
)

func main() {
	const (
		a1 = iota
		a2 = 100
		a3 = iota
	)
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a2: %v\n", a2)
	fmt.Printf("a3: %v\n", a3)
}

//运行结果
a1: 0
a2: 100
a3: 2

go注释

注释的形式

  • 单行注释。 以//打头
  • 多行注释。连续多行以//打头,或者在段前使用/*,段尾使用*/
  • 多行注释之间不能出现空行
  • NOTE: 引人注意,TODO:将来需要优化,Deprecated:变量或函数强烈建议不要再使用
  • 注释行前加缩进即可写代码

注释的位置

  • 包注释。在package xxx的上方。一个包只需要在一个地方写包注释,通常会专门写一个doc.go,里面只有一行package xxx和关于包的注释
  • 结构体注释。 在type xxx struct上方
  • 函数注释。在func xxx() 上方
  • 行注释。 在行上方或者右侧

go语言数据类型

在go语言中,数据类型用于声明函数和变量。

数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

go语言按类别有以下几种数据类型:

  • 布尔值

    • 布尔类型的值可以是常量 true和false。一个简单的例子: var a bool = true
  • 数字类型

    • 整型int和浮点型float32、float64,go语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
  • 字符串类型

    • 字符串就是一串固定长度的字符连接起来的字符序列。go的字符串是由单个字节连接起来的。go语言的字符串的字节使用utf-8编码标识unicode文本
  • 派生类型

    • 包括:(a) 指针类型(Pointer) (b) 数组类型 (c) 结构化类型 (d) Channel类型 (e) 函数类型 (f)切片类型 (g)接口类型(interface) (h) Map类型

数字类型

go也有基于架构的类型,例如:int、uint和uintptr。

  • uint8
    • 无符号8位整型(0到255)
  • uint16
    • 无符号16位整型(0到65535)
  • uint32
    • 无符号32位整型(0到4294967295)
  • uint64
    • 无符号64位整型(0到18446744073709551615)
  • int8
    • 有符号8位整型(-128到127)
  • int16
    • 有符号16位整型(-32768到32767)
  • int32
    • 有符号32位整型(-2147483648到2147483647)
  • int64
    • 有符号64位整型(-9223372036854775808到9223372036854775807)

浮点型

  • float32
    • IEEE-754 32位浮点型数
  • float64
    • IEEE-754 64位浮点型数
  • complex64
    • 32位实数和虚数
  • complex128
    • 64位实数和虚数

其他数字类型

  • byte 类型uint8
  • rune 类型 int32
  • uint32或64位
  • int与uint一样大小
  • uintptr无符号整型,用于存放一个指针

go语言布尔类型

go语言中的布尔类型有两个常量值:true和false。布尔类型经常使用在条件判断语句或者循环语句,也可以用在逻辑表达式中。

package main

import "fmt"

func main() {
	var b1 bool = true
	var b2 bool = false
	var b3 = true
	var b4 = false

	b5 := true
	b6 := false

	fmt.Printf("b1: %v\n", b1)
	fmt.Printf("b2: %v\n", b2)
	fmt.Printf("b3: %v\n", b3)
	fmt.Printf("b4: %v\n", b4)
	fmt.Printf("b5: %v\n", b5)
	fmt.Printf("b6: %v\n", b6)
}

//结果
b1: true
b2: false
b3: true
b4: false
b5: true
b6: false
用在条件判断中
package main

import "fmt"

func main() {
	age := 18
	if age >= 18 {
		fmt.Println("你已经成年了")
	} else {
		fmt.Println("你还没成年")
	}
}

//结果
你已经成年了
用在循环语句中
package main

import "fmt"

func main() {
	count := 10
	for i := 0; i < count; i++ {
		fmt.Printf("i=%v\n", i)
	}
}
//结果
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
用在逻辑表达式中
package main

import (
	"fmt"
)

func main() {
	age := 18
	gender := "男"

	if age >= 18 && gender == "男" {
		fmt.Println("你是成年男子")
	}
}

//结果
你是成年男子
注意:不能使用0和非0表示真假
package main

func main() {
	i := 1
	if i {
		//编译错误
	}
}

go语言数字类型

go语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码

go也有基于架构的类型,例如int、uint和uintptr。

这些类型的长度都是允许程序所在的操作系统类型所决定的:

  • int和uint 在32位操作系统上,它们均使用32位(4个字节),在64位操作系统上,均使用64位(8个字节)
  • uintptr的长度被设定为足够存放一个指针接口。

go语言中没有float类型。(只要float32和float64) 没有double类型。

与操作系统架构无关类型都有固定的大小,并在类型的名称中就可以看出来:

  • uint8
    • 无符号8位整型(0到255)
  • uint16
    • 无符号16位整型(0到65535)
  • uint32
    • 无符号32位整型(0到4294967295)
  • uint64
    • 无符号64位整型(0到18446744073709551615)
  • int8
    • 有符号8位整型(-128到127)
  • int16
    • 有符号16位整型(-32768到32767)
  • int32
    • 有符号32位整型(-2147483648到2147483647)
  • int64
    • 有符号64位整型(-9223372036854775808到9223372036854775807)
浮点型
  • float32
    • IEEE-754 32位浮点型数
  • float64
    • IEEE-754 64位浮点型数

int型是计算最快的类型。

整型的零值为0,浮点型的零值为0.0。

实例
package main

import (
	"fmt"
	"math"
	"unsafe"
)

func main() {
	var i8 int8
	var i16 int16
	var i32 int32
	var i64 int64
	var ui8 uint8
	var ui16 uint16
	var ui32 uint32
	var ui64 uint64

	fmt.Printf("%T %dB %v~%v\n", i8, unsafe.Sizeof(i8), math.MinInt8, math.MaxInt8)
	fmt.Printf("%T %dB %v~%v\n", i16, unsafe.Sizeof(i16), math.MinInt16, math.MaxInt16)
	fmt.Printf("%T %dB %v~%v\n", i32, unsafe.Sizeof(i32), math.MinInt32, math.MaxInt32)
	fmt.Printf("%T %dB %v~%v\n", i64, unsafe.Sizeof(i64), math.MinInt64, math.MaxInt64)
	fmt.Printf("%T %dB %v~%v\n", ui8, unsafe.Sizeof(ui8), 0, math.MaxUint8)
	fmt.Printf("%T %dB %v~%v\n", ui16, unsafe.Sizeof(ui16), 0, math.MaxUint16)
	fmt.Printf("%T %dB %v~%v\n", ui32, unsafe.Sizeof(ui32), 0, math.MaxUint32)
	fmt.Printf("%T %dB %v~%v\n", ui64, unsafe.Sizeof(ui64), 0, uint64(math.MaxUint64))

	var f32 float32
	var f64 float64

	fmt.Printf("%T %dB %v~%v\n", f32, unsafe.Sizeof(f32), -math.MaxFloat32, math.MaxFloat32)
	fmt.Printf("%T %dB %v~%v\n", f64, unsafe.Sizeof(f64), -math.MaxFloat64, math.MaxFloat32)

	var ui uint
	ui = uint(math.MaxUint64)
	fmt.Printf("%T %dB %v~%v\n", ui, unsafe.Sizeof(ui), 0, ui)

	var imax, imin int
	imax = int(math.MaxInt64)
	imin = int(math.MinInt64)
	fmt.Printf("%T %dB %v~%v\n", imax, unsafe.Sizeof(imax), imin, imax)
}


//结果
int8 1B -128~127
int16 2B -32768~32767
int32 4B -2147483648~2147483647
int64 8B -9223372036854775808~9223372036854775807
uint8 1B 0~255
uint16 2B 0~65535
uint32 4B 0~4294967295
uint64 8B 0~18446744073709551615
float32 4B -3.4028234663852886e+38~3.4028234663852886e+38
float64 8B -1.7976931348623157e+308~3.4028234663852886e+38
uint 8B 0~18446744073709551615
int 8B -9223372036854775808~9223372036854775807
以二进制、八进制或十六进制浮点数的格式定义数字
package main

import "fmt"

func main() {
	//十进制
	var a int = 10
	fmt.Printf("%d \n", a)
	fmt.Printf("%b \n", a)

	//八进制
	var b int = 077
	fmt.Printf("%o \n", b)

	//十六进制
	var c int = 0xff
	fmt.Printf("%x \n", c)
	fmt.Printf("%X \n", c)
}

//结果
10 
1010 
77 
ff 
FF 

浮点型

go语言支持两种浮点型数:float32和float64。这两种浮点型数据格式遵循IEEE 754标准:float32的浮点数的最大范围约为3.4e38,可以使用常量定义: math.MaxFloat32。float64的浮点数的最大范围约为1.8e308,可以使用常量定义: math.MaxFloat64。

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Printf("%f\n", math.Pi)
	fmt.Printf("%.2f\n", math.Pi)
}

//结果
3.141593
3.14

复数

complex64和complex128

var c1 complex64
c1 = 1 + 2i

var c2 complex128
c2 = 2 + 3i

fmt.Println(c1)
fmt.Println(c2)

复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位

golang字符串

一个go语言字符串是一个任意字节的常量序列。

go语言字符串字面量

在Go语言中,字符串字面量使用双引号 "" 或者反引号 ' 来创建。双引号用来创建可解析的字符串,支持转义,但不能用来引用多行;反引号用来创建原生的字符串字面量,可能由多行组成,但不支持转义,并且可以包含除了反引号外其他所有字符。双引号创建可解析的字符串应用最广泛,反引号用来创建原生的字符串则多用于书写多行消息,HTML以及正则表达式。

实例:
package main

import "fmt"

func main() {
	var s string = "hello world"
	var s1 = "hello world"
	var s2 = "hello world"
	var s3 string = `
		line1
		line2
		line3
	`
	fmt.Printf("s: %v\n", s)
	fmt.Printf("s1: %v\n", s1)
	fmt.Printf("s2: %v\n", s2)
	fmt.Printf("s3: %v\n", s3)
}

字符串连接
package main

import "fmt"

func main() {
	s1 := "fx"
	s2 := "666"
	msg := s1 + s2
	fmt.Printf("msg: %v\n", msg)
}
//结果
msg: fx666
使用fmt.Sprintf() 函数
package main

import "fmt"

func main() {
	name := "fx"
	age := "18"
	msg := fmt.Sprintf("%s,%s", name, age)
	fmt.Printf("msg: %v\n", msg)
}

//结果
msg: fx,18
strings.Join()
package main

import (
	"fmt"
	"strings"
)

func main() { 
	name := "fx"
	age := "18"
	s := strings.Join([]string{name, age}, "-")
	fmt.Printf("s: %v\n", s)

}
// 运行结果
s: fx-18
buffer.WriteString()
package main

import (
	"bytes"
	"fmt"
)

func main() {
	var buffer bytes.Buffer
	buffer.WriteString("fx")
	buffer.WriteString(",")
	buffer.WriteString("18")
	fmt.Printf("buffer.String(): %v\n", buffer.String())
}

go语言字符串转义字符

转义符 含义
\r 回车符(返回行首)
\n 换行符(直接跳到下一行的同列位置)
\t 制表符
\' 单引号
\" 双引号
\ 反斜杠
实例
package main

import "fmt"

func main() {
	// \r
	s1 := "hello \r world!"
  fmt.Printf("s1: %v\n", s1)
	// \n
	s2 := "hello \n world!"
  fmt.Printf("s2: %v\n", s2)
	// \t
	s3 := "hello\tword"
  fmt.Printf("s3: %v\n", s3)
	// \\
	s4 := "c:\\pro\\cc"
	fmt.Printf("s4: %v\n", s4)
}
go字符串切片操作
package main

import "fmt"

func main() {
	s := "hello world"
	a := 2
	b := 5
	fmt.Printf("s[a]: %v\n", s[a])
	fmt.Printf("s[a:b]: %v\n", s[a:b])
	fmt.Printf("s[a:]: %v\n", s[a:])
	fmt.Printf("s[:b]: %v\n", s[:b])
}
//运行结果
s[a]: 108
s[a:b]: llo
s[a:]: llo world
s[:b]: hello

go语言字符串常用方法

方法 介绍
len(str) 求长度
+或者 fmt.Sprintf 拼接字符串
strings.Split 分隔
strings.contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Index(),strings.LastIndex() 字符出现的位置
strings.Join(a[]string, sep string) join操作
strings.ToLower(),strings.ToUpper() 转成小写/大写
实例:
package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "hello world"
  //求长度
	fmt.Printf("len(s): %v\n", len(s))
  //以空格分隔
	fmt.Printf("strings.Split(s, \" \"): %v\n", strings.Split(s, " "))
  // 判断hello是否存在
	fmt.Printf("strings.Contains(s, \"hello\"): %v\n", strings.Contains(s, "hello"))
  //转换成小写
	fmt.Printf("strings.ToLower(s): %v\n", strings.ToLower(s))
  //转换成大写
	fmt.Printf("strings.ToUpper(s): %v\n", strings.ToUpper(s))
  //判断是否以hello开头
	fmt.Printf("strings.HasPrefix(s, \"hello\"): %v\n", strings.HasPrefix(s, "hello"))
  //判断是否以world结尾
	fmt.Printf("strings.HasSuffix(s, \"world\"): %v\n", strings.HasSuffix(s, "world"))
  //查看第一个l所在的索引位置
	fmt.Printf("strings.Index(s, \"ll\"): %v\n", strings.Index(s, "ll"))
  //查看最后一个l所在的索引位置
	fmt.Printf("strings.LastIndex(s, \"l\"): %v\n", strings.LastIndex(s, "l"))
	//字符串拼接
	name := "fx"
	age := "18"
	str1 := strings.Join([]string{name, age}, "-")
	fmt.Printf("str1: %v\n", str1)
}

golang格式化输出

下面实例使用到的结构体

type Website struct {
  Name string
}
//定义结构体变量
var site = Website{Name:"baidu.com"}

占位符

普通占位符

占位符 说明 举例 输出
%v 相应值的默认格式,任何变量都可以输出 fmt.Printf("site: %v\n", site) site:
%#v 打印结构体 fmt.Printf("site: %#v\n", site) site: main.Website
%T 打印类型 fmt.Printf("site: %T\n", site) site: main.Website
%% 百分号 fmt.Println("%%") %%
实例:
import "fmt"

type Website struct {
	Name string
}

func main() {
	site := Website{Name: "www.baidu.com"}
	//变量输出
	fmt.Printf("site: %v\n", site)
	//结构输出
	fmt.Printf("site: %#v\n", site)
	//打印类型
	fmt.Printf("site: %T\n", site)
	a := 1
	fmt.Printf("a: %T\n", a)

	fmt.Println("%%")
}
布尔占位符
占位符 说明 举例 结果
%t 单词true或者false fmt.Printf("t: %t\n", true) true
实例:
package main
func main() {
	t := true
	f := false
	fmt.Printf("t: %t\n", t)
	fmt.Printf("f: %t\n", f)
}

整数占位符

  • %b
    • 二进制表示
  • %c
    • 相应的Unicode码点所表示的字符
  • %d
    • 十进制表示
  • %o
    • 八进制表示
  • %q
    • 单引号围绕的字符字母值,由Go语法安全地转义
  • %x
    • 十六进制表示
  • %X
    • 十六进制表示,字母形式为大写A-F
  • %U
    • Unicode格式,U+1234,等同于"U+%04X"
实例:
package main

import "fmt"

func main() {
	i := 8
	//变量返回
	fmt.Printf("i: %v\n", i)
	//二进制表示
	fmt.Printf("i: %b\n", i)
	//Unicode码点字符
	fmt.Printf("i: %c\n", i)
	//十进制表示
	fmt.Printf("i: %d\n", i)
	//八进制表示
	fmt.Printf("i: %o\n", i)
	//单引号围绕的字符字面值
	fmt.Printf("i: %q\n", i)
	//十六进制
	fmt.Printf("i: %x\n", i)
	fmt.Printf("i: %X\n", i)
	//Unicode格式
	fmt.Printf("i: %U\n", i)
}

浮点数和复数的组成部分(实部和虚部)

  • %b
    • 无小数部分的,指数为二的幂的科学计数法
  • %e
    • 科学计数法,例如:-123456p-78 1.020000e+01
  • %E
    • 科学计数法,例如:-1234.456e+78 1.020000E+01
  • %f
    • 有小数点而无指数,例如 123.456
  • %g
    • 根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0) 输出
  • %G
    • 根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0) 输出

字符串与字节切片

  • %s
    • 输出字符串
  • %q
    • 双引号围绕这字符串
  • %x
    • 十六进制,小写字母
  • %X
    • 十六进制,大写字母
实例:
package main

import "fmt"

func main() {
	s := "hello world"
	fmt.Printf("s: %s\n", s)
	fmt.Printf("s: %q\n", s)
	fmt.Printf("s: %x\n", s)
	fmt.Printf("s: %X\n", s)
}
指针
  • %p
    • 十六进制表示,前缀0X
实例
package main

import "fmt"

func main() {
	x := 100
	p := &x
	fmt.Printf("p: %p\n", p)
}

golang运算符

go语言内置的运算符有:

1、算术运算符

2、关系运算符

3、逻辑运算符

4、位运算符

5、赋值运算符

算术运算符

运算符 描述
+ 相加
- 相减
* 相乘
/ 相除
% 求余
注意:++ (自增)和 --(自减) 在go语言中是单独的语句,并不是运算符。
实例:
package main

import "fmt"

func main() {
	a := 100
	b := 20
	fmt.Printf("(a + b): %v\n", (a + b))
	fmt.Printf("(a - b): %v\n", (a - b))
	fmt.Printf("(a * b): %v\n", (a * b))
	fmt.Printf("(a / b): %v\n", (a / b))
	x := a % b
	fmt.Printf("x: %v\n", x)

	c := 100
	c++
	fmt.Printf("c: %v\n", c)

	d := 100
	d--
	fmt.Printf("d: %v\n", d)
}
//结果
(a + b): 120
(a - b): 80
(a * b): 2000
(a / b): 5
x: 0
c: 101
d: 99

关系运算符

运算符 描述
== 检查两个值是否相等,如果相等返回true否则返回false
!= 检查两个值是否不相等,如果相等返回true否则返回false
> 检查左边值是否大于右边值,如果是返回true否则返回false
>= 检查左边值是否大于等于右边值,如果是返回true否则返回false
< 检查左边值是否小于右边值,如果是返回true否则返回false
<= 检查左边值是否小于于等于右边值,如果是返回true否则返回false
实例:
package main

import "fmt"

func main() {
	a := 10
	b := 5
	fmt.Printf("(a == b): %v\n", (a == b))
	fmt.Printf("(a != b): %v\n", (a != b))
	fmt.Printf("(a > b): %v\n", (a > b))
	fmt.Printf("(a >= b): %v\n", (a >= b))
	fmt.Printf("(a < b): %v\n", (a < b))
	fmt.Printf("(a <= b): %v\n", (a <= b))
}
//返回结果
(a == b): false
(a != b): true
(a > b): true
(a >= b): true
(a < b): false
(a <= b): false

逻辑运算符

运算符 描述
&&
||
!
实例
package main

import "fmt"

func main() {
	a := true
	b := false

	r := a && b
	fmt.Printf("r: %v\n", r)

	r = a || b
	fmt.Printf("r: %v\n", r)

	fmt.Printf("a: %v\n", !a)
}

位运算符

运算符 描述
& 参与运算的两数各对应的二进位与。(两位均为1才为1)
| 参与运算的两数各对应的二进位或。(两位有一个为1就为1)。
^ 参与运算的两数各对应的二进位相异或,当对应的二进位相异时,结果为1。(两位不一样则为1)
<< 左移n位就是乘以2的n次方。"a<<b"是把a的各二进位全部左移b位,高位丢弃,低位补0。
>> 左移n位就是除以2的n次方。"a>>b"是把a的各二进位全部右移b位。
实例:
package main

import "fmt"

func main() {
	a := 4
	fmt.Printf("a: %b\n", a)
	b := 8
	fmt.Printf("b: %b\n", b)

	fmt.Printf("(a & b): %v, %b\n", (a & b), (a & b))
	fmt.Printf("(a | b): %v, %b\n", (a | b), (a | b))
	fmt.Printf("(a ^ b): %v, %b\n", (a ^ b), (a ^ b))
	fmt.Printf("(a << b): %v, %b\n", (a << b), (a << b))
	fmt.Printf("(a >> b): %v, %b\n", (a >> b), (a >> b))
}

赋值运算符

运算符 描述
= 简单的赋值运算符,将一个表达式的赋值给一个左值
+= 相加后再赋值
-= 相减后再赋值
*= 相乘后再赋值
/= 相除后再赋值
%= 求余后再赋值
<<= 左移后再赋值
>>= 右移后再赋值
&= 按位与后赋值
|= 按位或后赋值
^= 按位异或后赋值
实例
package main

import "fmt"

func main() {
	var a int
	a = 100
	fmt.Printf("a: %v\n", a)
	a += 1
	fmt.Printf("a: %v\n", a)
	a -= 1
	fmt.Printf("a: %v\n", a)
	a *= 1
	fmt.Printf("a: %v\n", a)
	a /= 1
	fmt.Printf("a: %v\n", a)
}

golang if语句

go语言if语句语法

if 布尔表达式 {
  /* 在布尔表达式为 true 时执行 */
}
注意:在go语言中布尔表达式不用使用扩容。

go语言if语句实例演示

//实例一:
package main

import (
	"fmt"
)

func test1() {
	var flag = true
	if flag {
		fmt.Println("flag is true")
	}
	fmt.Println("程序运行结束")
}
func main() {
	test1()
}

// 运行结果
flag is true
程序运行结束



//实例二:
package main

import "fmt"

func main() {
	a := 1
	b := 2

	if a > b {
		fmt.Println(a)
	} else {
		fmt.Println(b)
	}
}

//运行结果
2


//实例三:根据年龄判断是否成年
package main

import "fmt"

func main() {
	age := 20
	if age > 18 {
		fmt.Println("你已经成年了")
	}
	fmt.Println("程序运行结束")
}

//运行结果
你已经成年了
程序运行结束

//实例四: 初始化变量可以声明在布尔值里面,注意它的作用域

package main

import "fmt"

func main() {
	if age := 20; age > 18 {
		fmt.Println("你已经成年")
	}
	fmt.Println("程序运行结束")
}
//运行结果
你已经成年
程序运行结束

//实例五: 不能使用0或者非0

package main

import "fmt"

func main() {
	a := 1
	if a {   //编译失败
		fmt.Println("hare")
	}
	fmt.Println("程序运行结束")
}

go语言if语句使用提示:

  1. 不需要使用扩容将条件包含起来
  2. 大括号{}必须存在,即使只要一行语句
  3. 左括号必须在if或else的同一行
  4. 在if之后,条件语句之前,可以在添加变量初始化语句,使用;进行分隔

go语言if else语句

go语言的if else语句语法

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

go语言if else语句实例

比较两个数的大小
package main

import "fmt"

func main() {
	a := 1
	b := 2
	if a > b {
		fmt.Printf("(a > b): %v\n", "a > b")
	} else {
		fmt.Printf("(a <= b): %v\n", "a <= b")
	}
}
用户输入
package main

import "fmt"

func main() {
	var name string
	var age int
	var email string
	fmt.Println("请输入name,age,email 用空格分隔:")
	fmt.Scan(&name, &age, &email)

	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
	fmt.Printf("email: %v\n", email)
}
判断一个数是奇数还是偶数
package main

import "fmt"

func f2() {
	var s int
	fmt.Println("请输入一个数字:")
	fmt.Scan(&s)

	if s%2 == 0 {
		fmt.Println("s 是偶数")
	} else {
		fmt.Println("s 是奇数")
	}
	fmt.Println("s 的值是:", s)
}
func main() {
	f2()
}
判断是否成年
package main

import (
	"fmt"
)

func main() {
	age := 18
	if age >= 18 {
		fmt.Println("已经成年!")
	} else {
		fmt.Println("未成年")
	}
}
特殊写法
package main

import (
	"fmt"
)

func main() {
  if age := 18; age >= 18 {
		fmt.Println("已经成年!")
	} else {
		fmt.Println("未成年")
	}
}

go语言if else if语句

go语言if else if 语法

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

go语言中的if else if语法实例

根据分数判断等级
package main

import "fmt"

func f5() {
	var score int
	fmt.Println("请输入你的分数:")
	fmt.Scan(&score)
	if score >= 60 && score <= 70 {
		fmt.Println("C")
	} else if score > 70 && score <= 90 {
		fmt.Println("B")
	} else if score > 90 {
		fmt.Println("A")
	} else {
		fmt.Println("D")
	}
}

func main() {
	f5()
}

输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母
package main

import (
	"fmt"
)

func main() {
	// Sunday Monday Tuesday Wednesday Thursday Friday Saturday
	var c string
	fmt.Println("请输入一个字符:")
	fmt.Scan(&c)

	if c == "S" {
		fmt.Println("请输入第二个字符:")
		fmt.Scan(&c)

		if c == "a" {
			fmt.Println("Saturday")
		} else if c == "u" {
			fmt.Println("Sunday")
		} else {
			fmt.Println("输入错误")
		}
	} else if c == "F" {
		fmt.Println("Friday")
	} else if c == "M" {
		fmt.Println("Monday")
	} else if c == "T" {
		fmt.Println("请输入第二个字符:")
		fmt.Scan(&c)
		if c == "h" {
			fmt.Println("Thursday")
		} else if c == "u" {
			fmt.Println("Tuesday")
		} else {
			fmt.Println("输入错误")
		}
	} else if c == "W" {
		fmt.Println("Wednesday")
	} else {
		fmt.Println("输入错误!")
	}
}

golang中嵌套if语句

go语言if语句可以嵌套多级进行判断。

go语言if嵌套语法

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

go语言if嵌套实例

判断三个数的大小
package main

import "fmt"

// a>b b>c  a最大
// b>a b>c  b最大 else c最大

func main() {
	a := 100
	b := 200
	c := 3

	if a > b {
		if a > c {
			fmt.Println("a最大")
		}
	} else {
		if b > c {
			fmt.Println("b最大")
		} else {
			fmt.Println("c最大")
		}
	}
}
判断是男生还是女生,还有是否成年
package main

import "fmt"

func main() {
	gender := "女生"
	age := 16

	if gender == "男生" {
		fmt.Println("男生")
		if age > 18 {
			fmt.Println("成年")
		} else {
			fmt.Println("未成年")
		}
	} else {
		fmt.Println("女生")
		if age > 18 {
			fmt.Println("成年")
		} else {
			fmt.Println("未成年")
		}
	}
}

golang switch语句

go语言中的switch语句,可以非常容易的判断多个值的情况。

go语言中switch语句的语法

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

go语言中switch语句实例

判断成绩
package main

import (
	"fmt"
)

func f() {
	grade := "A"
	switch grade {
	case "A":
		fmt.Println("优秀")
	case "B":
		fmt.Println("良好")
	default:
		fmt.Println("一般")
	}

}
func main() {
	f()
}
//运行结果
优秀
多添加判断

go语言switch语句,可以同时匹配多个条件,中间用逗号分隔,有其中一个匹配成功即可。

package main

import (
	"fmt"
)

func f2() {
	day := 5
	switch day {
	case 1, 2, 3, 4, 5:
		fmt.Println("工作日")
	case 6, 7:
		fmt.Println("休息日")
	default:
		fmt.Println("非法输入")
	}
}
func main() {
	f2()
}

//运行结果
工作日
case可以是条件表达式
package main

import (
	"fmt"
)

func f3() {
	score := 90
	switch {
	case score >= 90:
		fmt.Println("好好休息")
	case score < 90 && score >= 80:
		fmt.Println("好好学习吧")
	default:
		fmt.Println("玩命学习")
	}
}
func main() {
	f3()
}

//运行结果
好好休息
fallthrough可以执行满足条件的下一个case
package main

import (
	"fmt"
)

func f4() {
	a := 100
	switch a {
	case 100:
		fmt.Println("100")
		fallthrough
	case 200:
		fmt.Println("200")
	case 300:
		fmt.Println("300")
	}
}
func main() {
	f4()
}

//运行结果
100
200

go语言中switch语句的注意事项

  1. 支持多条件匹配
  2. 不同的case之间不使用break分隔,默认只会执行一个case。
  3. 如果想要执行多个case,需要使用fallthrough关键字,也可用break终止。
  4. 分支还可以使用表达式, 例如 a>10

golang for循环语句

go语言中的for循环,只要for关键字,去除了像其他语言中的while和do while。

go语言for循环语法

for 初始化语句;条件表达式;结束语句{
  循环体语句
}
注意:for表达式不用加括号

go语言for循环实例

循环输出1到10
package main

import "fmt"

func f() {
	for i := 1; i <= 10; i++ {
		fmt.Printf("i: %v\n", i)
	}
}
func main() {
	f()
}
//运行结果
i: 1
i: 2
i: 3
i: 4
i: 5
i: 6
i: 7
i: 8
i: 9
i: 10
初始化条件和结束条件都可以省略
package main

import "fmt"

func f2() {
	i := 1  //初始条件
	for i <= 10 {
		fmt.Printf("i: %v\n", i)
		i++ //结束条件
	}
}
func main() {
	f2()
}
//运行结果
i: 1
i: 2
i: 3
i: 4
i: 5
i: 6
i: 7
i: 8
i: 9
i: 10
永真循环
package main

import "fmt"


func f3() {
	for {
		fmt.Println("6666")
	}
}

func main() {
	f3()
}

//运行结果
6666
6666
6666
6666
6666

golang for range循环

go语言中可以使用for range遍历数组、切片、字符串、map及通道(channel)。提通过for range遍历的返回值有以下规律:

  1. 数组、切片、字符串返回索引和值。
  2. map返回键和值
  3. 通道(channel)只返回通道内的值。

go语言for range实例

循环数组
package main

import "fmt"

func f() {
	var a = [5]int{1, 2, 3, 4, 5}
	for i, v := range a {
		fmt.Printf("i: %d, v: %v\n", i, v)
	}
}

func main() {
	f()
}

//运行结果
i: 0, v: 1
i: 1, v: 2
i: 2, v: 3
i: 3, v: 4
i: 4, v: 5
循环切片
package main

import "fmt"


func f2() {
	var s = []int{1, 2, 3, 4, 5, 6}
	for _, v := range s {
		fmt.Printf("v: %v\n", v)
	}
}
func main() {
	f2()
}
//运行结果
v: 1
v: 2
v: 3
v: 4
v: 5
v: 6
循环map
package main

import "fmt"

func f3() {
	m := make(map[string]string, 0)
	m["name"] = "tom"
	m["age"] = "20"
	m["email"] = "fx@gmail.com"

	for key, value := range m {
		fmt.Printf("%v:%v\n", key, value)
	}
}
func main() {
	f3()
}
//运行结果
name:tom
age:20
email:fx@gmail.com
循环字符串
package main

import "fmt"

func f4() {
	var s = "hello world"
	for i, v := range s {
		fmt.Printf("i: %d, v: %c\n", i, v)
	}
}
func main() {
	f4()
}

golang流程控制关键字break

break语句可以结束 for、switch和select的代码块

go语言使用break注意事项

  1. 单独在select中使用break和不使用break没有啥区别。
  2. 单独在表达式switch语句,并且没有fallthough,使用break和不使用break没有啥区别。
  3. 单独在表达式switch语句,并且有fallthough,使用break能够终止fallthough后面的case语句的执行。
  4. 带标签的break,可以跳出多层select/switch作用域。让break更加灵活,写法更加简单灵活,不需要使用控制变量一层一层跳出循环,没有带break的只能跳出当前语句块。

go语言break关键字实例

跳出循环
package main

import "fmt"

func f() {
	for i := 0; i < 10; i++ {
		if i == 5 {
			break
		}
		fmt.Printf("i: %v\n", i)
	}
}
func main() {
	f()
}

//运行结果
i: 0
i: 1
i: 2
i: 3
i: 4

跳出switch
package main

import "fmt"

func f2() {
	i := 2
	switch i {
	case 1:
		fmt.Println("1")
		break
	case 2:
		fmt.Println("2")
		break
		fallthrough
	case 3:
		fmt.Println("3")
		break
	}
}
func main() {
	f2()
}

//运行结果
2
跳出标签处
package main

import "fmt"

func f3() {
MYLABEL:
	for i := 0; i < 10; i++ {
		fmt.Printf("i: %v\n", i)
		if i >= 5 {
			break MYLABEL
		}
	}
	fmt.Println("END....")
}
func main() {
	f3()
}

//运行结果
i: 0
i: 1
i: 2
i: 3
i: 4
i: 5
END....

golang关键字continue

continue只能用在循环中,在go中只能在for循环中,它可以终止本次循环,进行下一次循环。

在continue语句后添加标签时,表示开始标签对应的循环。

go语言continue实例

输出1到10之间的偶数
package main

import "fmt"

func f() {
	for i := 1; i < 10; i++ {
		if i%2 == 0 {
			fmt.Printf("i: %v\n", i)
		} else {
			continue
		}
	}
}
func main() {
	f()
}

//运行结果
i: 2
i: 4
i: 6
i: 8
跳转到label
func f2() {
	for i := 0; i < 10; i++ {
	MYLABEL:
		for j := 0; j < 10; j++ {
			if i == 2 && j == 2 {
				continue MYLABEL
			}
			fmt.Printf("%v,%v\n", i, j)
		}
	}
}
func main() {
	f()
	f2()
}

//运行结果
i: 2
i: 4
i: 6
i: 8
0,0
0,1
0,2
0,3
0,4
0,5
0,6
0,7
0,8
0,9
1,0
1,1
1,2
1,3
1,4
1,5
1,6
1,7
1,8
1,9
2,0
2,1
2,3
2,4
2,5
2,6
2,7
2,8
2,9
3,0
3,1
3,2
3,3
3,4
3,5
3,6
3,7
3,8
3,9
4,0
4,1
4,2
4,3
4,4
4,5
4,6
4,7
4,8
4,9
5,0
5,1
5,2
5,3
5,4
5,5
5,6
5,7
5,8
5,9
6,0
6,1
6,2
6,3
6,4
6,5
6,6
6,7
6,8
6,9
7,0
7,1
7,2
7,3
7,4
7,5
7,6
7,7
7,8
7,9
8,0
8,1
8,2
8,3
8,4
8,5
8,6
8,7
8,8
8,9
9,0
9,1
9,2
9,3
9,4
9,5
9,6
9,7
9,8
9,9

golang流程控制关键字goto

goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。

go语言中使用goto语句能简化一些代码的实现过程。例如双层嵌套的for循环要退出时:

go语言关键字goto实例

跳转到指定的标签
package main

import "fmt"

func f() {
	i := 1
	if i >= 2 {
		fmt.Println("2")
	} else {
		goto END
	}
END:
	fmt.Println("END....")
}
func main() {
	f()
}
//运行结果
END....
跳出多层循环
package main

import "fmt"

func f2() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if i >= 2 && j >= 2 {
				goto END
			}
			fmt.Printf("%v, %v\n", i, j)
		}
	}
END:
	fmt.Println("END.....")
}
func main() {
	f2()
}

//运行结果
0, 0
0, 1
0, 2
0, 3
0, 4
0, 5
0, 6
0, 7
0, 8
0, 9
1, 0
1, 1
1, 2
1, 3
1, 4
1, 5
1, 6
1, 7
1, 8
1, 9
2, 0
2, 1
END.....

golang数组

数组是相同数据类型的一组数据的集合,数组一旦定义长度不能修改,数组可以通过下标(或者索引)来访问元素。

go语言数组的定义

数组定义的语法如下:

var variable_name [SIZE] variable_type

variable_name: 数组名称

SIZE: 数组长度,必须是常量

variable_type:数组保存元素的类型

实例
package main

import "fmt"

func test1() {
	var a1 [2]int
	var a2 [3]string
	//打印类型
	fmt.Printf("a1: %T\n", a1)
	fmt.Printf("a2: %T\n", a2)
}
func main() {
	test1()
}

//运行结果
a1: [2]int
a2: [3]string
//数组和长度和元素类型共同组成了数组的类型。

go语言数组的初始化

初始化,就是给数组的元素赋值,没有初始化的数组,默认元素值都是零值,布尔值是false,字符串是空字符串。

数据如何切分
package main

import "fmt"

func test1() {
	var s1 = [...]int{1, 2, 3, 4, 5, 6, 7, 8}
	fmt.Printf("s1: %v\n", s1)
	s2 := s1[:]
	fmt.Printf("s2: %v\n", s2)
	s3 := s1[:4]
	fmt.Printf("s3: %v\n", s3)
	s4 := s1[2:5]
	fmt.Printf("s4: %v\n", s4)
	s5 := s1[2:]
	fmt.Printf("s5: %v\n", s5)
}
func main() {
	test1()
}

//运行结果
s1: [1 2 3 4 5 6 7 8]
s2: [1 2 3 4 5 6 7 8]
s3: [1 2 3 4]
s4: [3 4 5]
s5: [3 4 5 6 7 8]
没有初始化的数组
package main

import "fmt"


func test2() {
	var a1 [2]int
	var a2 [3]string
	var a3 [2]bool
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a2: %v\n", a2)
	fmt.Printf("a3: %v\n", a3)
}
func main() {
	test2()
}

//运行结果
a1: [0 0]
a2: [  ]
a3: [false false]
使用初始化列表
package main

import "fmt"

func test3() {
	var a1 = [2]int{1, 2}
	var a2 = [3]string{"fx", "xy", "mm"}
	var a3 = [2]bool{true, false}

	a4 := [2]int{2, 4}
	fmt.Printf("a1: %v\n", a1)
	fmt.Printf("a2: %v\n", a2)
	fmt.Printf("a3: %v\n", a3)
	fmt.Printf("a4: %v\n", a4)
}
func main() {
	test3()
}

//运行结果
a1: [1 2]
a2: [fx xy mm]
a3: [true false]
a4: [2 4]
省略数组长度

数组长度可以省略,使用...代替,更加初始化值得数量自动推断,例如

package main

import "fmt"

func test4() {
	var a = [...]int{1, 2}
	var s = [...]string{"hello", "world", "xxx"}
	var b = [...]bool{true, false}
	a1 := [...]int{3, 4}
	fmt.Printf("a: %v\n", a)
	fmt.Printf("s: %v\n", s)
	fmt.Printf("b: %v\n", b)
	fmt.Printf("a1: %v\n", a1)
}
func main() {
	test4()
}

//运行结果
a: [1 2]
s: [hello world xxx]
b: [true false]
a1: [3 4]
指定索引值的方式来初始化

可以通过指定所有的方式来初始化,未指定所有的默认为零值。

package main

import "fmt"


func test5() {
	var a = [...]int{0: 1, 2: 2}
	var s = [...]string{1: "fx", 2: "kite"}
	var b = [...]bool{2: true, 5: false}
	a1 := [...]int{1: 1, 3: 3}
	fmt.Printf("a: %v\n", a)
	fmt.Printf("s: %v\n", s)
	fmt.Printf("b: %v\n", b)
	fmt.Printf("a1: %v\n", a1)

}
func main() {
	test5()
}
//运行结果
a: [1 0 2]
s: [ fx kite]
b: [false false true false false false]
a1: [0 1 0 3]

go语言访问数组元素

可以通过下标的方式,来访问数组元素,数组的最大下标为数组的长度-1,大于这个下标会发生数组越界。

访问数组元素

实例:
package main

import "fmt"

func test1() {
	var a1 [2]int
	a1[0] = 100
	a1[1] = 200
	fmt.Printf("a1[0]: %v\n", a1[0])
	fmt.Printf("a1[1]: %v\n", a1[1])
	fmt.Println("------------")
	//修改a[0] a[1]
	a1[0] = 500
	a1[1] = 600
	fmt.Printf("a1[0]: %v\n", a1[0])
	fmt.Printf("a1[1]: %v\n", a1[1])

	//数组长度越界
	//a1[3] = 400
}
func main() {
	test1()
}
//运行结果
a1[0]: 100
a1[1]: 200
------------
a1[0]: 500
a1[1]: 600
数组长度
package main

import "fmt"

func test2() {
	var a1 = [3]int{1, 2, 3}
	fmt.Printf("len(a1): %v\n", len(a1))
	var a2 = [...]int{1, 2, 3, 4, 5, 6, 7}
	fmt.Printf("len(a2): %v\n", len(a2))
}
func main() {
	test2()
}

//运行结果
len(a1): 3
len(a2): 7
根据数据长度变量数组

可以根据数组长度,通过for循环的方式来遍历数组,数组的长度可以使用len函数获得。

实例:
package main

import "fmt"

func test3() {
  //数组的遍历  1.根据长度和下标
	var a1 = [3]int{1, 2, 3}
	for i := 0; i < len(a1); i++ {
		fmt.Printf("a1[%v]: %v\n", i, a1[i])
	}
}
func main() {
	test3()
}
//运行结果
a1[0]: 1
a1[1]: 2
a1[2]: 3
使用for range数组

还可以使用for range循环来遍历数组,ranage返回数组下标和对应的值

实例:
package main

import (
	"fmt"
)


func test4() {
	var a1 = [4]int{1, 2, 3, 4}
	for i, v := range a1 {
		fmt.Printf("a1[%v]: %v\n", i, v)
	}
}
func main() {
	// test1()
	// test2()
	// test3()
	test4()
}
//运行结果
a1[0]: 1
a1[1]: 2
a1[2]: 3
a1[3]: 4

golang切片

数组是固定长度,可以容纳相同数据类型的元素的集合。当长度固定时,使用还是带来一些限制,比如:我们申请的长度太大浪费内存,太小又不够用。

鉴于上述原因,我们有了go语言的切片,可以把切片理解为,可变长度的数组,其实它底层就是使用数组实现的,增加了自动扩容功能。切片(Slice)是一个拥有相同类型元素的可变长度的序列。

go语言切片的语法

声明一个切片和声明一个数组类似,只要不添加长度就可以了

var identifier []type

切片是引用类型,可以使用make函数来创建切片:

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

也可以简写为
slice1 := make([]type, len)

也可以指定容量,其中capacity为可选参数。

make([]T, length,capaciyh)

这里len是数组的长度并且也是切片的初始长度。

go语言切片实例

//变量方式声明
package main

import "fmt"


func test1() {
	var s1 []int
	var s2 []string
	fmt.Printf("s1: %v\n", s1)
	fmt.Printf("s2: %v\n", s2)
}
func main() {
	test1()
}
//运行结果
s1: []
s2: []


//make函数方式声明
package main

import "fmt"

func test2() {
	var s2 = make([]int, 2)
	fmt.Printf("s2: %v\n", s2)
}

func main() {
	test2()
}
//运行结果
s2: [0 0]

go语言切片的长度和容量

切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。

实例:
package main

import "fmt"


func test3() {
	var s1 = []int{1, 2, 3, 4, 5}
	fmt.Printf("len(s1): %v\n", len(s1))
	fmt.Printf("cap(s1): %v\n", cap(s1))
	fmt.Printf("s1[0]: %v\n", s1[0])
}
func main() {
	test3()
}
//运行结果
len(s1): 5
cap(s1): 5
s1[0]: 1

golang切片的初始化

切片的初始化方法很多,可以直接初始化,也可以使用数组初始化等。

切片如何切分
package main

import "fmt"

func test6() {
	var s1 = []int{1, 2, 3, 4, 5, 6}
	s2 := s1[0:3]
	fmt.Printf("s2: %v\n", s2)
	s3 := s1[3:]
	fmt.Printf("s3: %v\n", s3)
	s4 := s1[2:5]
	fmt.Printf("s4: %v\n", s4)
	s5 := s1[:]
	fmt.Printf("s5: %v\n", s5)
}

func main() {
	test6()
}
//运行结果
s2: [1 2 3]
s3: [4 5 6]
s4: [3 4 5]
s5: [1 2 3 4 5 6]
直接初始化
package main

import "fmt"

func test4() {
	s := []int{1, 2, 3, 4, 5}
	fmt.Printf("s: %v\n", s)
}
func main() {
	test4()
}

//运行结果
s: [1 2 3 4 5]
使用数组初始化
package main

import "fmt"

func test5() {
	arr := [...]int{1, 2, 3}
  //取数组所有元素
	s1 := arr[:]
	fmt.Printf("s1: %v\n", s1)
}

func main() {
	test5()
}
//运行结果
s1: [1 2 3]
使用数组的部分元素初始化(切片表达式)

切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。切片表达式中的low和high表示一个索引范围(左包含,右不包含),得到的切片长度=high-low,容量等于得到的切片的底层数组的容量。

package main

import "fmt"

func test8() {
	arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
	s1 := arr[2:5]
	fmt.Printf("s1: %v\n", s1)
	s2 := arr[2:]
	fmt.Printf("s2: %v\n", s2)
	s3 := arr[:3]
	fmt.Printf("s3: %v\n", s3)
}
func main() {
	test8()
}
//运行结果
s1: [3 4 5]
s2: [3 4 5 6 7 8]
s3: [1 2 3]

go语言切片的遍历

切片的遍历和数字的遍历非常类似,可以使用for循环索引遍历,或者for range循环。

for循环索引遍历
package main

import "fmt"

func test() {
	var s1 = []int{1, 2, 3, 4, 5}
	l := len(s1)
	for i := 0; i < l; i++ {
		fmt.Printf("s1[%v]: %v\n", i, s1[i])
	}
}
func main() {
	test()
}
//运行结果
s1[0]: 1
s1[1]: 2
s1[2]: 3
s1[3]: 4
s1[4]: 5
for range遍历
package main

import "fmt"


func test2() {
	var s1 = []int{1, 2, 3, 4, 5, 6}
	for i, v := range s1 {
		fmt.Printf("s1[%v]: %v\n", i, v)
	}
}
func main() {
	test2()
}
//运行结果
s1[0]: 1
s1[1]: 2
s1[2]: 3
s1[3]: 4
s1[4]: 5
s1[5]: 6

go语言切边元素的添加和删除copy

切片是一个动态数组,可以使用append()函数添加元素,go语言中并没有删除切片元素的专用方法,我们可以使用切边本身的特性来删除元素。由于切片是引用类型,通过赋值的方法,会修改原有内容,go提供了copy()函数来拷贝切边。

添加元素
package main

import "fmt"

func test() {
	s1 := []int{}
	s1 = append(s1, 1)
	s1 = append(s1, 2)
	s1 = append(s1, 3, 4, 5) //添加多个元素
	fmt.Printf("s1: %v\n", s1)

	s3 := []int{3, 4, 5}
	s4 := []int{1, 2}
	s4 = append(s4, s3...)
	fmt.Printf("s4: %v\n", s4)
}
func main() {
	test()
}
//运行结果
s1: [1 2 3 4 5]
s4: [1 2 3 4 5]
删除元素
公式:a = append(a[:index], a[index+1]...)
package main

import "fmt"

func test2() {
	var s1 = []int{1, 2, 3, 4, 5}
	s1 = append(s1[:2], s1[3:]...)
	fmt.Printf("s1: %v\n", s1)
}
func main() {
	test2()
}
修改元素
package main

import "fmt"

func test3() {
	var s1 = []int{1, 2, 3, 4, 5}
	s1[1] = 100
	fmt.Printf("s1: %v\n", s1)
}
func main() {
	test3()
}

//运行结果
s1: [1 100 3 4 5]
查看元素
package main

import "fmt"

func test4() {
	var s1 = []int{1, 2, 3, 4, 5}
	var keys = 2
	for i, v := range s1 {
		if v == keys {
			fmt.Printf("i: %v\n", i)
		}
	}
}
func main() {
	test4()
}
//运行结果
i: 1
copy
package main

import "fmt"

func test5() {
  //直接赋值 内存地址相同 s2的元素修改了s1也会跟着修改
	var s1 = []int{1, 2, 3, 4, 5, 6}
	s2 := s1
	s2[0] = 100
	fmt.Printf("s1: %v\n", s1)
	fmt.Printf("s2: %v\n", s2)
}
func main() {
	test5()
}
//运行结果
s1: [100 2 3 4 5 6]
s2: [100 2 3 4 5 6]



package main

import "fmt"

func test6() {
	var s1 = []int{1, 2, 3, 4, 5}
	var s2 = make([]int, 4)
	copy(s2, s1)
	s2[0] = 100
	fmt.Printf("s1: %v\n", s1)
	fmt.Printf("s2: %v\n", s2)
}

func main() {
	test6()
}
//运行结果
s1: [1 2 3 4 5]
s2: [100 2 3 4]

golang map

map是一种key:value 键值对的数据结构容器。map内部实现是哈希表(hash)。

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

map是引用类型。

map的语法格式

可以使用内建函数make也可以使用map关键字来定义map

/*  声明变量,默认map是nil */
var map_variable map[key_data_type]value_date_type

/* 使用make函数 */
map_variable = make(map[key_data_type]value_date_type)
map_variable: map变量名称
key_data_type: key的数据类型
value_date_type: 值的数据类型
实例

下面声明一个保存个人信息的map

package main

import "fmt"

func test() {
	//类型的声明
	var m3 map[string]string
	//初始化一个空的map
	m3 = make(map[string]string)
	fmt.Printf("m3: %v\n", m3)

	m1 := make(map[string]string)
	m1["name"] = "fx"
	m1["age"] = "20"
	m1["email"] = "fangxing@xxx.com"
	fmt.Printf("m1: %v\n", m1)

	m2 := map[string]string{
		"name":  "xy",
		"age":   "22",
		"email": "xy@xxx.com",
	}
	fmt.Printf("m2: %v\n", m2)
}
func main() {
	test()
}
//运行结果
m3: map[]
m1: map[age:20 email:fangxing@xxx.com name:fx]
m2: map[age:22 email:xy@xxx.com name:xy]
访问map

可以通过下标key获得其值,例如:

package main

import "fmt"

func test2() {
	m1 := map[string]string{
		"name":  "fx",
		"age":   "18",
		"email": "fx@xxx.com",
	}
	name := m1["name"]
	age := m1["age"]
	email := m1["email"]
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
	fmt.Printf("email: %v\n", email)
}
func main() {
	test2()
}

//运行结果
name: fx
age: 18
email: fx@xxx.com
判断某个键是否存在

go语言中有个判断map中键是否存在的特殊写法,格式如下:

value, ok := map[key]

如果ok为true,存在,否则,不存在。

实例:
package main

import "fmt"

func test3() {
	var m1 = map[string]string{
		"name":  "fx",
		"age":   "20",
		"email": "fx@xxx.com",
	}
	var k1 = "name"
	var k2 = "age1"
	v, ok := m1[k1]
	fmt.Printf("v: %v\n", v)
	fmt.Printf("ok: %v\n", ok)
	fmt.Println("------------")
	v, ok = m1[k2]
	fmt.Printf("v: %v\n", v)
	fmt.Printf("ok: %v\n", ok)
}
func main() {
	test3()
}
//运行结果
v: fx
ok: true
------------
v: 
ok: false

go语言变量map

可以使用for range 循环进行map遍历,得到key和value值。

遍历key
package main

import "fmt"

func test1() {
	var m1 = map[string]string{
		"name":  "fx",
		"age":   "20",
		"email": "fx@xxx.com",
	}
	for key := range m1 {
		fmt.Printf("key: %v\n", key)
	}
}
func main() {
	test1()
}
//运行结果
key: email
key: name
key: age
变量key和value
package main

import "fmt"

func test2() {
	var m1 = map[string]string{
		"name":  "fx",
		"age":   "20",
		"email": "fx@xxx.com",
	}
	for key, value := range m1 {
		fmt.Printf("key: %v  value: %v\n", key, value)

	}
}
func main() {
	test2()
}
//运行结果
key: name  value: fx
key: age  value: 20
key: email  value: fx@xxx.com

golang函数

golang函数简介

函数的go语言中的一级公民,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数名称、参数列表和返回值类型,这些构成了函数的签名(signature)。

go语言中函数特性

  1. go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。
  2. go语言中不允许函数重载(overload),也就是说不允许函数同名。
  3. go语言中的函数不能嵌套函数,但可以嵌套匿名函数。
  4. 函数是一个值,可以将函数赋值给变量,使得这个变量也可以成为函数。
  5. 函数可以作为参数传递给另一个函数。
  6. 函数的返回值可以是一个函数。
  7. 函数调用的时候,如果参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
  8. 函数参数可以没有名称。

go语言中函数的定义和调用

函数在使用之前必须先定义,可以调用函数来完成某个任务。函数可以重复调用,从而达到代码重用。

go语言函数定义语法

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

go语言函数定义实例

定义一个求和函数
package main

import "fmt"

func sum(a int, b int) (ret int) {
	ret = a + b
	return ret
}
func main() {
	r := sum(5, 7)
	fmt.Printf("r: %v\n", r)
}
//运行结果
r: 12
定义一个比较两个数大小的函数
package main

import "fmt"

func compare(a int, b int) (max int) {
	if a > b {
		max = a
	} else {
		max = b
	}
	return max
}
func main() {
	m := compare(10, 9)
	fmt.Printf("m: %v\n", m)
}
//运行结果
m: 10

go语言函数调用

当我们需要完成某个任务时,可以调用函数来完成。调用函数要传递参数,如果有返回值可以获得返回值。

func main() {
	r := sum(5, 7)
	fmt.Printf("r: %v\n", r)
}
//运行结果
r: 12


func main() {
	m := compare(10, 9)
	fmt.Printf("m: %v\n", m)
}
//运行结果
m: 10

golang函数的返回值

函数可以有0或者多个返回值,返回值需要指定数据类型,返回值通过return关键字来指定。

return可以有参数,可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。

  1. return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
  2. 当返回值有名称时,必须使用扩容范围,逗号分隔,即使只有一个返回值。
  3. 但即使返回值命名了,return中也可以强制指定其它返回值的名称,也就是说return的优先级更高
  4. 命名的返回值是预先声明好的,在函数内部可以直接调用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义。
  5. return中可以有表达式,但不能出现赋值表达式,这和其它语言可能有所不同。例如return a+b 是正确的,但是return c=a+b是错误的。
没有返回值
package main

import "fmt"

func f1() {
	fmt.Println("我没有返回值,只是进行一些计算")
}

func main() {
	f1()
}
//返回结果
我没有返回值,只是进行一些计算
有一个返回值
package main

import "fmt"

func sum(a int, b int) (ret int) {
	ret = a + b
	return ret
}

func main() {
	r := sum(4, 6)
	fmt.Printf("r: %v\n", r)
}
//返回结果
r: 10


package main

import "fmt"

func sum1(a int, b int) int {
	return a + b
}

func main() {
	r1 := sum1(10, 20)
	fmt.Printf("r1: %v\n", r1)
}
//运行结果
r1: 30
多个返回值,且在return中指定返回的内容
package main

import "fmt"

func f2() (name string, age int) {
	name = "二狗"
	age = 20
	return name, age
}
func main() {
	name, age := f2()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}
//运行结果
name: 二狗
age: 20



package main

import "fmt"

func f3() (name string, age int) {
	name = "二狗"
	age = 20
	return
}

func main() {
	name, age := f3()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}
//运行结果
name: 二狗
age: 20
return覆盖命名返回值,返回值名称没有被使用
package main

import "fmt"

func f4() (name string, age int) {
	n := "二狗"
	a := 20
	return n, a
}
func main() {
	n, a := f4()
	fmt.Printf("n: %v\n", n)
	fmt.Printf("a: %v\n", a)
}
//运行结果
n: 二狗
a: 20
Go中经常会使用其中一个返回值作为函数是否执行成功,是否有错误信息的判断条件。例如 return value,exists、return value,ok、return value,err等。
当函数的返回值过多时,例如有4个以上的返回值。应该将这些返回值收集到容器中,然后以返回容器的方式去返回。例如,同一个类型的返回值可以放进切片(slice)中,不同类型的返回值可以放进map中。
但函数有多个返回值时,如果其中某个或某几个返回值不想使用,可以通过下划线_来丢弃这些返回值。例如下面的f1函数两个返回值。调用该函数时,丢弃了第二个返回值b,只保留了第一个返回值a赋值给了变量a。
package main

import "fmt"

func f5() (int, int) {
	return 1, 2
}

func main() {
	_, x := f5()
	fmt.Printf("x: %v\n", x)
}

//运行结果
x: 2

golang函数的参数

go语言函数可以有0或者多个参数,参数需要指定数据类型。

声明函数时的参数列表叫做形参,调用时传递的参数叫做实参。

go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问、修改的也是这个副本。

go语言可以使用变长参数,有时候不能确定参数的个数,可以使用变长参数,可以在函数定义语句的参数部分,使用ARGS...TYPE的方式。这时会将...代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE。

go语言函数的参数实例

go语言传参
package main

import "fmt"

//形参
func sum(a int, b int) int {
	return a + b
}
func main() {
	//实参
	r := sum(5, 8)
	fmt.Printf("r: %v\n", r)
}
//结果
r: 13
演示参数传递,按值传递
package main

import "fmt"

//copy
func f1(a int) {
	a = 200
  fmt.Printf("a: %v\n", a)
}

func main() {
	a := 500
	f1(a)
	fmt.Printf("a: %v\n", a)
}
//结果
a: 200
a: 500

从运行结果可以看到,调用函数f1后,a的值并没有改变,说明参数传递是拷贝了一个副本,也就是拷贝了一份新的内容进行计算。

map、slice、interface、channel这些数据类型本身就是指针类型的,所以就算是拷贝也是拷贝的指针,拷贝后的参数依然指向底层数据结构,所以修改它们可能会影响外部数据结构的值。
package main

import "fmt"

func f1(a []int) {
	a[0] = 100
}

func main() {
	a := []int{1, 2, 3}
	f1(a)
	fmt.Printf("a: %v\n", a)
}
//结果
a: [100 2 3]
从运行结果发现,调用函数后,slice内容被改变了。
变长参数
package main

import "fmt"

func f3(args ...int) {
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}

func f4(name string, ok bool, args ...int) {
	fmt.Printf("name: %v\n", name)
	fmt.Printf("ok: %v\n", ok)
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}

func main() {
	f3(1, 2, 3, 5)
	fmt.Println("---------------")
	f3(6, 7, 8, 9, 10)
	fmt.Println("---------------")
	f4("fx", true, 1, 2, 3, 4, 5)
}
//运行结果
v: 1
v: 2
v: 3
v: 5
---------------
v: 6
v: 7
v: 8
v: 9
v: 10
---------------
name: fx
ok: true
v: 1
v: 2
v: 3
v: 4
v: 5

golang函数类型与函数变量

可以使用type关键字来定义一个函数类型,语法格式如下:

type fun func(int, int) int

上面语句定义了一个fun函数类型,它是一种函数类型,这种函数接收两个int类型的参数并且返回一个int类型的返回值。

下面我们定义两个这样结构的两个函数,一个求和,一个比较大小:

func sum(a int, b int) int {
  return a + b
}


func max(a int, b int) int {
  if a > b {
    return a 
  } else {
    return b
  }
}

下面定义一个func函数类型,把sum和max赋值给它

package main

import "fmt"

func sum(a int, b int) int {
	return a + b
}

func max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}

func main() {
	type f1 func(int, int) int
	var ff f1
	ff = sum
	r := ff(1, 2)
	fmt.Printf("r: %v\n", r)

	ff = max
	r = ff(5, 6)
	fmt.Printf("r: %v\n", r)
}

//运行结果
r: 3
r: 6

golang高阶函数

go语言的函数,可以作为函数的参数,传递给了另外一个函数,作为另外一个函数的返回值返回。

go语言函数作为参数
package main

import "fmt"

func sayHello(name string) {
	fmt.Printf("Hello,%s", name)
}

func test(name string, f func(string)) {
	f(name)
}
func main() {
	test("fangxing", sayHello)
}
//运行结果
Hello,fangxing
go语言函数作为返回值