目录
Go 语言函数
函数参数
函数如果使用参数,该变量可称为函数的形参。
形参就像定义在函数体内的局部变量。
调用函数,可以通过两种方式来传递参数:
传递类型 | 描述 |
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 | |
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 |
默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
函数用法
函数用法 | 描述 |
函数定义后可作为另外一个函数的实参数传入 | |
闭包是匿名函数,可在动态编程中使用 | |
方法就是一个包含了接受者的函数 |
Go 语言变量作用域
局部变量
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
以下实例中 main() 函数使用了局部变量 a, b, c:
func localVariable() {
/* 声明局部变量 */
var a, b, c int
/* 初始化参数 */
a = 10
b = 20
c = a + b
fmt.Printf("结果 a = %d, b = %d, c = %d", a, b, c)
}
全局变量
在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。
全局变量可以在任何函数中使用,以下实例演示了如何使用全局变量:
var g int
func globalVariable() {
/* 声明局部变量 */
var a, b int
/* 初始化参数 */
a = 10
b = 10
g = a + b
fmt.Printf("a = %d, b = %d, g = %d", a, b, g)
}
形式参数
形式参数会作为函数的局部变量来使用。实例如下:
/* 声明全局变量 */
var a int = 10
func formalParameters() {
/* 声明局部变量 */
var a int = 10
var b int = 10
var c int = 0
fmt.Printf("main 中 a = %d,b = %d, c = %d\n", a, b, c)
c = sum(a, b)
fmt.Printf("main 中 a = %d,b = %d, c = %d\n", a, b, c)
}
/* 函数定义-两数相加 */
func sum(a, b int) int {
fmt.Printf("sum 函数中 a = %d\n", a)
fmt.Printf("sum 函数中 b = %d\n", b)
return a + b
}
Go 语言数组
Go 语言提供了数组类型的数据结构。
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
相对于去声明 number0, number1, ..., number99 的变量,使用数组形式 numbers[0], numbers[1] ..., numbers[99] 更加方便且易于扩展。
数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。
初始化数组
func array() {
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 balance2 = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
// balance2 := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Printf("balance %v", balance)
fmt.Printf("balance2 %v", balance2)
}
Go 语言结构体
Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
定义结构体
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:
type struct_variable_type struct{
member definition
member definition
...
member definition
}
type Books struct {
title string
author string
subject string
book_id int
}
func structuralMorphology() {
//创建一个新的结构体
fmt.Println(Books{"Go", "Go", "Go", 1})
//key => value 格式
fmt.Println(Books{title: "go", author: "go", subject: "go", book_id: 2})
//忽略的字段为0或空
fmt.Println(Books{title: "1", book_id: 3})
}
Go 语言切片(Slice)
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片初始化
s := [] int {1, 2, 3}
直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
s := arr[:]
初始化切片 s,是数组 arr 的引用。
s := arr[startIndex : endIndex]
将 arr 中从下标 startIndex 到 endIndex -1 下的元素创建为一个新的切片。
s := arr[startIndex :]
默认 endIndex 时将表示一直到arr的最后一个元素。
s := arr[: endIndex]
默认 startIndex 时将表示从 arr 的第一个元素开始。
s1 := s[startIndex : endIndex]
通过切片 s 初始化切片 s1。
s := make([]int, len, cap)
len() 和 cap()
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
func printSlice(x []int) {
fmt.Printf("len = %d cap = %d slice = %v \n", len(x), cap(x), x)
}
printSlice(make([]int, 3, 5))
//len = 3 cap = 5 slice = [0 0 0]
Go 语言Map(集合)
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
func fMap() {
/* 创建集合 */
var countryCapitalMap map[string]string
countryCapitalMap = make(map[string]string)
/* map 插入key - value, 各个国家对应的首都*/
countryCapitalMap["China"] = "beijing"
countryCapitalMap["France"] = "bali"
countryCapitalMap["Italy"] = "luoma"
countryCapitalMap["Japan"] = "dongjing"
countryCapitalMap["India"] = "xindeli"
/* 使用键输出地图值 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
/* 查看元素集合是否存在 */
capital, ok := countryCapitalMap["America"]
fmt.Println(capital)
fmt.Println(ok)
if ok {
fmt.Println("America的首都是", capital)
} else {
fmt.Println("America的首都不存在")
}
}
delete()
delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key
func deleteMap() {
/* 创建map */
countryCapitalMap := map[string]string{"China": "beijing", "Japan": "riben", "France": "bali"}
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])
}
}
Go 语言接口
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
package main
import (
"fmt"
)
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iphone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
Go 并发
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
goroutine 语法格式:
go 函数名(参数列表)
例如:
go f(x, y, z)
开启一个新的gorountine:
f(x, y, z)
Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
通道(channel)
通道(channel)是用来传递数据的一个数据结构。
通道可用于两个goroutine之间传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
ch <- v //把 v 发送到通道 ch
v := <-ch // 从 ch 接收数据, 并把值赋给 v
声明一个通道很简单。使用 chan 关键字即可,通道在使用前必须先创建,
ch := make(chan int)
func passageway() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sums(s[:len(s)/2], c)
go sums(s[len(s)/2:], c)
x, y := <-c, <-c //从通道c中接收
fmt.Println(x, y, x+y)
}
func sums(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum //把 sum 发送到通道 c
}