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 |
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语句使用提示:
- 不需要使用扩容将条件包含起来
- 大括号{}必须存在,即使只要一行语句
- 左括号必须在if或else的同一行
- 在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语句的注意事项
- 支持多条件匹配
- 不同的case之间不使用break分隔,默认只会执行一个case。
- 如果想要执行多个case,需要使用fallthrough关键字,也可用break终止。
- 分支还可以使用表达式, 例如 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遍历的返回值有以下规律:
- 数组、切片、字符串返回索引和值。
- map返回键和值
- 通道(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"] = "[email protected]"
for key, value := range m {
fmt.Printf("%v:%v\n", key, value)
}
}
func main() {
f3()
}
//运行结果
name:tom
age:20
email:[email protected]
循环字符串
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注意事项
- 单独在select中使用break和不使用break没有啥区别。
- 单独在表达式switch语句,并且没有fallthough,使用break和不使用break没有啥区别。
- 单独在表达式switch语句,并且有fallthough,使用break能够终止fallthough后面的case语句的执行。
- 带标签的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"] = "[email protected]"
fmt.Printf("m1: %v\n", m1)
m2 := map[string]string{
"name": "xy",
"age": "22",
"email": "[email protected]",
}
fmt.Printf("m2: %v\n", m2)
}
func main() {
test()
}
//运行结果
m3: map[]
m1: map[age:20 email:[email protected] name:fx]
m2: map[age:22 email:[email protected] name:xy]
访问map
可以通过下标key获得其值,例如:
package main
import "fmt"
func test2() {
m1 := map[string]string{
"name": "fx",
"age": "18",
"email": "[email protected]",
}
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: [email protected]
判断某个键是否存在
go语言中有个判断map中键是否存在的特殊写法,格式如下:
value, ok := map[key]
如果ok为true,存在,否则,不存在。
实例:
package main
import "fmt"
func test3() {
var m1 = map[string]string{
"name": "fx",
"age": "20",
"email": "[email protected]",
}
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": "[email protected]",
}
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": "[email protected]",
}
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: [email protected]
golang函数
golang函数简介
函数的go语言中的一级公民,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数名称、参数列表和返回值类型,这些构成了函数的签名(signature)。
go语言中函数特性
- go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。
- go语言中不允许函数重载(overload),也就是说不允许函数同名。
- go语言中的函数不能嵌套函数,但可以嵌套匿名函数。
- 函数是一个值,可以将函数赋值给变量,使得这个变量也可以成为函数。
- 函数可以作为参数传递给另一个函数。
- 函数的返回值可以是一个函数。
- 函数调用的时候,如果参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
- 函数参数可以没有名称。
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中的函数可以有多个返回值。
- return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
- 当返回值有名称时,必须使用扩容范围,逗号分隔,即使只有一个返回值。
- 但即使返回值命名了,return中也可以强制指定其它返回值的名称,也就是说return的优先级更高
- 命名的返回值是预先声明好的,在函数内部可以直接调用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义。
- 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语言函数作为返回值
标签:语言,package,fmt,基础,func,Printf,go,main
From: https://www.cnblogs.com/fxxy/p/17088676.html