你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

GO-函数及结构体

2022/1/2 14:01:09

1 函数

1.1 普通函数

定义
1. 无参数无返回值
func 函数名() {
	函数体
}

2. 有参数有返回值并且指定变量名
func 函数名(参数 数据类型) (返回值 数据类型) {
	函数体
}

3. 有参数有返回值不指定的变量名
func 函数名(参数 数据类型) 数据类型 {
	函数体
}

4. 相同数据类型简写
func 函数名(参数1, 参数2 数据类型) (返回值1, 返回值2 数据类型) {
	函数体
}

5. 相同数据类型不定长参数
func 函数名(参数 ...数据类型) 数据类型 {
	函数体
}

package main

import "fmt"

func f1() {											// 无参数无返回值
	fmt.Println("this is f1")
}

func f2(x int) (y int) {							// 有参数有返回值,并命名
	fmt.Printf("this is f2, args: %d\n", x)
	return x
}

func f3(x int) int {								// 不命名
	fmt.Printf("this is f3, args: %d\n", x)
	return x
}

func f4(x, y int) (a, b int) {						// 相同类型简写
	fmt.Printf("This is f4, args: %d, %d\n", x, y)
	return x, y
}

func f5(x ...int) int {								// 不定长
	sum := 0
	fmt.Printf("this is f5, args: %v\n", x)
	for _, value := range x {
		sum += value
	}
	return sum
}

func main() {
	f1()
	fmt.Printf("return: %d\n", f2(123))
	fmt.Printf("return: %d\n", f3(456))
	x1, x2 := f4(123, 456)
	fmt.Printf("return: %d, %d\n", x1, x2)
	fmt.Printf("return: %d\n", f5(1, 2, 3, 4, 5, 6, 7, 8, 9))
}


输出:
this is f1
this is f2, args: 123
return: 123
this is f3, args: 456
return: 456
This is f4, args: 123, 456
return: 123, 456
this is f5, args: [1 2 3 4 5 6 7 8 9]
return: 45

1.2 匿名函数

匿名函数
func(参数 数据类型) (返回值 数据类型) {
	函数体
}
package main

import "fmt"

func f1() func() {
	fmt.Println("this is f1")
	return func() {						// 匿名函数
		fmt.Println("this is ff1")
	}
}

func main() {
	f1()()
}

输出:
this is f1
this is ff1

1.3 闭包函数

闭包
func 函数名(参数 数据类型) (函数类型) {
	变量名:=变量值
	return func(参数 数据类型)(返回值 数据类型){
		函数体
	}
}

package main

import "fmt"

func f1(x, y int) func() int {
	return func() int {
		return x + y
	}
}

func main() {
	fmt.Println(f1(1, 2)())
}

输出:
3

1.4 defer

return执行时机
返回值赋值 -> 运行defer -> RET指令
defer执行顺序:从下至上

package main

import "fmt"

func f1() {
	fmt.Println("this is f1")
	defer fmt.Println("defer 1")
	defer fmt.Println("defer 2")
	fmt.Println("f1 done")
}

func main() {
	f1()
}

输出:
this is f1
f1 done
defer 2
defer 1

1.5 递归

package main

import "fmt"

func f1(n int) int {
	if n == 1 {
		return 1
	}

	return n * f1(n-1)
}

func main() {
	fmt.Printf("return: %d\n", f1(5))
}

1.6 内置函数

函数描述
close主要用来关闭channel
len用来获得长度
new用来分配内存,主要是值类型:int、string、struct … 返回对应类型的指针
make用来分配内存,主要是引用类型:slice、map、chan … 返回对应类型
append用来追加元素到数组、slice中
panic/recover用来做错误处理

2 结构体

2.1 类型别名

类型别名是取一个别名,实际还是原来的数据类型
type 别名 = 数据类型
type byte = uint8
type rune = int32

2.2 自定义类型

基于数据类型创建一个新的数据类型
type 自定义类型 数据类型
type myInt int

2.3 结构体定义

类型名在同一个包内不可重复
字段名在结构体内必须唯一
名称首字母大写表示公开属性外部可以访问, 小写表示私有属性外部无法访问
type 类型名 struct {
	字段名 字段类型
	字段类型					// 匿名字段,每个类型只能存在一个, 通过点字段类型赋值取值
	...
}

匿名结构体
var 变量名 struct {
	字段名 字段类型
	...
}

type person struct {
	name string
	age  uint8
}

var animal struct {
	name string
	age  uint8
}

2.4 结构体实例化与初始化

基本实例化
var 变量名 结构体类型名

指针类型实例化
1. 变量名 := new(结构体类型名)
2. 变量名 := &结构体类型名{}

基本初始化
变量名.字段名 = 值

使用键值对初始化									// 没初始化的字段默认为零值
变量名 := 结构体类型名{字段名: 值,...}	
变量名 := &结构体类型名{字段名:, ...}			// 指针类型

使用值的列表初始化								// 按定义顺序传值,不可以与键值初始化混用, 必须初始化全部字段
变量名 := 结构体类型名{1,2, ...}
变量名 := &结构体类型名{1,2, ...}			// 指针类型

package main

import "fmt"

type person struct {
	name string
	age  uint8
}

var animal struct {
	name string
	age  uint8
}

func main() {
	var p1 person							// 基本实例化
	p2 := new(person)						// 实例化指针类型
	p3 := &person{name: "zzz", age: 21}		// 实例化指针类型并初始化
	p1.name = "www"							// 基本初始化
	p1.age = 18
	p2.name = "ccc"
	p2.age = 20
	animal.name = "xxx"
	animal.age = 19
	fmt.Printf("type: %T, value: %v\n", p1, p1)
	fmt.Printf("type: %T, value: %v\n", p2, p2)
	fmt.Printf("type: %T, value: %v\n", p3, p3)
	fmt.Printf("type: %T, value: %v", animal, animal)
}

输出:
type: main.person, value: {www 18}
type: *main.person, value: &{ccc 20}
type: *main.person, value: &{zzz 21}
type: struct { name string; age uint8 }, value: {xxx 19}

2.5 构造函数

一般构造函数命名格式为:new+结构体名
函数参数为字段值, 返回结构体的指针类型
最后一个字段后面一定要跟逗号
调用就是函数调用
func newPerson(name string, age uint8) *person {
	return &person{
		name: name,
		age: age,
	}
}
p4 := newPerson("ggg", 22)				// 调用		
fmt.Printf("type: %T, value: %v\n", p4, p4)

输出:
type: *main.person, value: &{ggg 22}

2.6 方法与接收者

方法属于特定的类型的函数
接收者变量一般为接收者类型首字母小写
func (接收者变量 接收者类型) 方法名(参数 参数类型) (返回值 返回值类型){
	函数体
}

func (p *person) eat(food string) {
	fmt.Printf("%s eat %s\n", p.name, food)
}

p4.eat("what")							// 调用

输出:
ggg eat what

2.7 结构体嵌套

package main

import "fmt"

type Addr struct {
	Province string
	City     string
}

type Contact struct {
	email string
	phone string
}

type person struct {
	name    string // 普通字段
	address Addr   // 普通嵌套
	Contact        // 匿名字段嵌套
}

func newPerson(name, province, city, email, phone string) *person {
	return &person{
		name: name,
		address: Addr{
			Province: province,
			City:     city,
		},
		Contact: Contact{
			email: email,
			phone: phone,
		},
	}
}

func main() {
	p1 := newPerson("www", "江苏省", "徐州市", "123@qq.com", "110120")
	fmt.Println(p1.name)
	fmt.Println(p1.address.Province)
	fmt.Println(p1.address.City)  // 嵌套取值
	fmt.Println(p1.Contact.email) // 匿名字段使用类型名作为字段名
	fmt.Println(p1.phone)         // 匿名字段可简写省略字段名
}

输出:
www
江苏省
徐州市
123@qq.com
110120

2.8 结构体与Json

包:encoding/json
序列化:json.Marshal(结构体)
反序列化:json.Unmarshal(byte类型的切片字符串, 结构体)
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`				// 标签指定序列化的字段名称
	Age  uint8
}

func main() {
	// 序列化
	p1 := &Person{"www", 18}
	data, err := json.Marshal(p1)				// err不是nil表示报错了
	fmt.Printf("%s, %v\n", data, err)

	// 反序列化
	p2 := &Person{}
	str := `{"name": "sss", "age": 19}`
	err2 := json.Unmarshal([]byte(str), p2)		// err2不是nil表示报错了
	fmt.Printf("%v, %v\n", p2, err2)
}

输出:
{"name":"www","Age":18}, <nil>
&{sss 19}, <nil>