上一篇文章
> Go入门(四)之工程管理、复合类型
一、面向对象编程
1、匿名组合
封装:通过方法实现
继承:通过匿名字段实现
多态:通过接口实现
(1)匿名字段初始化
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person //只有类型,没有名字,匿名字段
id int
addr string
}
func main() {
// 顺序初始化
var s1 Student = Student{Person{"wielun", 'm', 18}, 1, "bj"}
fmt.Println("s1 = ", s1)
// 自动推导类型
s2 := Student{Person{"wielun", 'm', 18}, 1, "bj"}
// %+v,显示更详细
fmt.Printf("s2 = %+v\n", s2)
// 制定成员初始化
s3 := Student{Person: Person{name: "wielun"}, id: 1}
fmt.Printf("s3 = %+v\n", s3)
}
结果:
s1 = {{wielun 109 18} 1 bj}
s2 = {Person:{name:wielun sex:109 age:18} id:1 addr:bj}
s3 = {Person:{name:wielun sex:0 age:0} id:1 addr:}
(2)操作成员
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person //只有类型,没有名字,匿名字段
id int
addr string
}
func main() {
s1 := Student{Person{"wielun", 'm', 18}, 1, "bj"}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
s1.name = "haha"
s1.sex = 'f'
s1.age = 22
s1.id = 666
s1.addr = "cd"
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
s1.Person = Person{"go", 'm', 18}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
}
结果:
wielun 109 18 1 bj
haha 102 22 666 cd
go 109 18 666 cd
(3)同名字段
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person
id int
addr string
name string // 和Person同名
}
func main() {
// 声明(定义一个变量)
var s Student
// 就近原则
s.name = "mike"
s.sex = 'm'
s.age = 18
s.addr = "bj"
// 显式调用
s.Person.name = "wielun"
fmt.Printf("s = %+v\n", s)
}
结果:
s = {Person:{name:wielun sex:109 age:18} id:0 addr:bj name:mike}
(4)非结构体匿名字段
package main
import "fmt"
type mystr string //自定义类型,给一个类型改名
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person //结构体匿名字段
int //基础类型的匿名字段
mystr
}
func main() {
s := Student{Person{"mike", 'm', 18}, 666, "hahaha"}
fmt.Printf("s = %+v\n", s)
fmt.Println(s.name, s.age, s.sex, s.int, s.mystr)
fmt.Println(s.Person, s.int, s.mystr)
}
结果:
s = {Person:{name:mike sex:109 age:18} int:666 mystr:hahaha}
mike 18 109 666 hahaha
{mike 109 18} 666 hahaha
(5)结构体指针类型匿名字段
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
*Person //指针类型
id int
addr string
}
func main() {
s1 := Student{&Person{"mike", 'm', 18}, 666, "bj"}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
// 先定义变量
var s2 Student
s2.Person = new(Person) //分配空间
s2.name = "wielun"
s2.sex = 'm'
s2.age = 18
s2.id = 222
s2.addr = "cd"
fmt.Println(s2.name, s2.sex, s2.age, s2.id, s2.addr)
}
结果:
mike 109 18 666 bj
wielun 109 18 222 cd
2、方法
(1)面向过程和对象函数的区别
面向对象只是换了一种表现形式
package main
import "fmt"
// 面向过程
func Add01(a, b int) int {
return a + b
}
// 面向对象,方法:给某个类型绑定一个函数
type long int
// tmp叫接收者,接收者就是传递的一个参数
func (tmp long) Add02(other long) long {
return tmp + other
}
func main() {
var result int
result = Add01(1, 1) // 普通函数调用方式
fmt.Println("result = ", result)
// 定义一个变量
var a long = 2
// 调用方法格式: 变量名.函数(所需参数)
r := a.Add02(3)
fmt.Println("r = ", r)
}
结果:
result = 2
r = 5
(2)为结构体类型添加方法
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
// 带有接收者的函数叫方法
func (tmp Person) PrintInfo() {
fmt.Println("tmp = ", tmp)
}
// 通过一个函数,给成员赋值
func (p *Person) SetInfo(n string, s byte, a int) {
p.name = n
p.sex = s
p.age = a
}
func main() {
// 定义同时初始化
p := Person{"mike", 'm', 18}
p.PrintInfo()
// 定义一个结构体变量
var p2 Person
(&p2).SetInfo("wielun", 'f', 22)
p2.PrintInfo()
}
结果:
tmp = {mike 109 18}
tmp = {wielun 102 22}
(3)值语义和引用语义
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
// 修改成员变量的值
// 参数为普通变量,非指针,值语义,一份拷贝
func (p Person) SetInfoVal(n string, s byte, a int) {
p.name = n
p.sex = s
p.age = a
fmt.Println("p = ", p)
fmt.Printf("SetInfoVal &p = %p\n", &p)
}
// 接收者为指针变量,引用传递
func (p *Person) SetInfoPointer(n string, s byte, a int) {
p.name = n
p.sex = s
p.age = a
fmt.Printf("SetInfoPointer p = %p\n", p)
}
func main() {
s1 := Person{"go", 'm', 22}
fmt.Printf("&s1 = %p\n", &s1)
// 值语义
s1.SetInfoVal("mike", 'm', 18)
fmt.Println("s1 = ", s1)
// 引用语义
(&s1).SetInfoPointer("mike1", 'f', 20)
fmt.Println("s1 = ", s1)
}
结果:
&s1 = 0xc000114440
p = {mike 109 18}
SetInfoVal &p = 0xc000114480
s1 = {go 109 22}
SetInfoPointer p = 0xc000114440
s1 = {mike1 102 20}
(4)方法集
用实例value和pointer调用方法(含匿名字段)不受方法集约束,编译器总是查找全部方法,并自动抓换receiver实参。
<1> 指针变量的方法集
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
func (p Person) SetInfoValue() {
fmt.Println("SetInfoValue")
}
func (p *Person) SetInfoPointer() {
fmt.Println("SetInfoPointer")
}
func main() {
// 结构体变量是一个指针变量,它能够调用那些方法,这些方法就是一个集合,简称方法集
p := &Person{"wielu", 'm', 18}
p.SetInfoPointer()
// 内部做的转换,先把指针p,转成*p后再调用
// (*p).SetInfoValue()
p.SetInfoValue()
}
结果:
SetInfoPointer
SetInfoValue
<2> 普通变量的方法集
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
func (p Person) SetInfoValue() {
fmt.Println("SetInfoValue")
}
func (p *Person) SetInfoPointer() {
fmt.Println("SetInfoPointer")
}
func main() {
p := Person{"wielu", 'm', 18}
p.SetInfoPointer()
// 内部先把p转换为&p在调用
p.SetInfoValue()
}
结果:
SetInfoPointer
SetInfoValue
(5)方法的继承
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
// Person类型,实现了一个方法
func (tmp *Person) PrintInfo() {
fmt.Printf("name = %s, sex = %c, age = %d\n", tmp.name, tmp.sex, tmp.age)
}
// 有一个学生,继承Person字段,成员和方法都继承
type Student struct {
Person
id int
addr string
}
func main() {
s := Student{Person{"wielun", 'm', 18}, 666, "cd"}
s.PrintInfo()
}
结果:
name = wielun, sex = m, age = 18
(6)方法的重写
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
// Person类型,实现了一个方法
func (tmp *Person) PrintInfo() {
fmt.Printf("name = %s, sex = %c, age = %d\n", tmp.name, tmp.sex, tmp.age)
}
// 有一个学生,继承Person字段,成员和方法都继承
type Student struct {
Person
id int
addr string
}
// 与Person同名,叫重写
func (tmp *Student) PrintInfo() {
fmt.Println("Student: tmp = ", tmp)
}
func main() {
s := Student{Person{"wielun", 'm', 18}, 666, "cd"}
// 就近原则
s.PrintInfo()
// 显式调用继承方法
s.Person.PrintInfo()
}
结果:
Student: tmp = &{{wielun 109 18} 666 cd}
name = wielun, sex = m, age = 18
(7)方法值
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
func (p Person) SetInfoValue() {
fmt.Printf("SetInfoValue: %p, %v\n", &p, p)
}
func (p *Person) SetInfoPointer() {
fmt.Printf("SetInfoPointer: %p, %v\n", p, p)
}
func main() {
p := Person{"wielun", 'm', 18}
fmt.Printf("main: %p, %v\n", &p, p)
p.SetInfoPointer()
// 保存方式入口地址
pFunc := p.SetInfoPointer //这个就是方法值,调用函数时,无需再传递接收者
pFunc()
vFunc := p.SetInfoValue
vFunc()
}
结果:
main: 0xc0000044a0, {wielun 109 18}
SetInfoPointer: 0xc0000044a0, &{wielun 109 18}
SetInfoPointer: 0xc0000044a0, &{wielun 109 18}
SetInfoValue: 0xc000004540, {wielun 109 18}
(8)方法表达式
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
func (p Person) SetInfoValue() {
fmt.Printf("SetInfoValue: %p, %v\n", &p, p)
}
func (p *Person) SetInfoPointer() {
fmt.Printf("SetInfoPointer: %p, %v\n", p, p)
}
func main() {
p := Person{"wielun", 'm', 18}
fmt.Printf("main: %p, %v\n", &p, p)
// 方法值
f := (*Person).SetInfoPointer
f(&p) //显式把接收者传递过去
f2 := (Person).SetInfoValue
f2(p)
}
结果:
main: 0xc000096440, {wielun 109 18}
SetInfoPointer: 0xc000096440, &{wielun 109 18}
SetInfoValue: 0xc0000964c0, {wielun 109 18}
3、接口
(1)概述
(2)接口的定义和实现
package main
import "fmt"
type Humaner interface {
// 方法只有声明,没有实现,由别的类型(自定义类型)实现
sayhi()
}
// Student实现了此方法
type Student struct {
name string
id int
}
func (tmp *Student) sayhi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
// Teacher实现了此方法
type Teacher struct {
addr string
group int
}
func (tmp *Teacher) sayhi() {
fmt.Printf("Teacher[%s, %d] sayhi\n", tmp.addr, tmp.group)
}
type MyStr string
// MyStr实现了此方法
func (tmp *MyStr) sayhi() {
fmt.Printf("MyStr[%s] sayhi\n", *tmp)
}
func main() {
// 定义接口类型的变量
var i Humaner
// 只要实现了此接口方法的类型,那么这个类型的变量(接收者类型)就可以给i赋值
s := &Student{"mike", 666}
i = s
i.sayhi()
t := &Teacher{"bj", 12}
i = t
i.sayhi()
var str MyStr = "hello wielun"
i = &str
i.sayhi()
}
结果:
Student[mike, 666] sayhi
Teacher[bj, 12] sayhi
MyStr[hello wielun] sayhi
(3)多态的表现
package main
import "fmt"
type Humaner interface {
// 方法只有声明,没有实现,由别的类型(自定义类型)实现
sayhi()
}
// Student实现了此方法
type Student struct {
name string
id int
}
func (tmp *Student) sayhi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
// Teacher实现了此方法
type Teacher struct {
addr string
group int
}
func (tmp *Teacher) sayhi() {
fmt.Printf("Teacher[%s, %d] sayhi\n", tmp.addr, tmp.group)
}
type MyStr string
// MyStr实现了此方法
func (tmp *MyStr) sayhi() {
fmt.Printf("MyStr[%s] sayhi\n", *tmp)
}
// 定义一个普通函数,函数的参数为接口类型
// 只有一个函数,可以有不同表现,多态
func WhoSayHi(i Humaner) {
i.sayhi()
}
func main() {
s := &Student{"mike", 666}
t := &Teacher{"bj", 12}
var str MyStr = "hello wielun"
WhoSayHi(s)
WhoSayHi(t)
WhoSayHi(&str)
fmt.Printf("------\n")
// 创建一个切片
x := make([]Humaner, 3)
x[0] = &str
x[1] = t
x[2] = &str
for _, i := range x {
i.sayhi()
}
}
结果:
Student[mike, 666] sayhi
Teacher[bj, 12] sayhi
MyStr[hello wielun] sayhi
------
MyStr[hello wielun] sayhi
Teacher[bj, 12] sayhi
MyStr[hello wielun] sayhi
(4)接口的继承
package main
import "fmt"
type Humaner interface { //子集
sayhi()
}
type Personer interface { //超集
Humaner //匿名字段,继承了sayhi
sing(lrc string)
}
// Student实现了此方法
type Student struct {
name string
id int
}
func (tmp *Student) sayhi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
func (tmp *Student) sing(lrc string) {
fmt.Println("Stuent sing:", lrc)
}
func main() {
// 定义一个变量
var i Personer
s := &Student{"wielun", 666}
i = s
i.sayhi() //继承过来的方法
i.sing("绿光")
}
结果:
Student[wielun, 666] sayhi
Stuent sing: 绿光
(5)接口转换
超集可以转换为子集,反过来不行
package main
import "fmt"
type Humaner interface { //子集
sayhi()
}
type Personer interface { //超集
Humaner //匿名字段,继承了sayhi
sing(lrc string)
}
// Student实现了此方法
type Student struct {
name string
id int
}
func (tmp *Student) sayhi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
func (tmp *Student) sing(lrc string) {
fmt.Println("Stuent sing:", lrc)
}
func main() {
var iPro Personer //超集
iPro = &Student{"wielun", 123}
var i Humaner //子集
i = iPro //超集转换为子集
i.sayhi()
}
结果:
Student[wielun, 123] sayhi
(6)空接口
空接口万能类型,保存任意类型的值
package main
import "fmt"
func main() {
var i interface{} = 1
fmt.Println("i = ", i)
}
结果:
i = 1
(7)类型断言(if)
package main
import "fmt"
type Student struct {
name string
id int
}
func main() {
i := make([]interface{}, 3)
i[0] = 1
i[1] = "hello go"
i[2] = Student{"wielun", 123}
// 类型查询,类型断言
for index, data := range i {
if value, ok := data.(int); ok == true {
fmt.Printf("x[%d] 类型为int, 内容为%d\n", index, value)
} else if value, ok := data.(string); ok == true {
fmt.Printf("x[%d] 类型为string, 内容为%s\n", index, value)
} else if value, ok := data.(Student); ok == true {
fmt.Printf("x[%d] 类型为Student, 内容为name = %s, id = %d\n", index, value.name, value.id)
}
}
}
结果:
x[0] 类型为int, 内容为1
x[1] 类型为string, 内容为hello go
x[2] 类型为Student, 内容为name = wielun, id = 123
(8)类型断言(switch)
package main
import "fmt"
type Student struct {
name string
id int
}
func main() {
i := make([]interface{}, 3)
i[0] = 1
i[1] = "hello go"
i[2] = Student{"wielun", 123}
for index, data := range i {
switch value := data.(type) {
case int:
fmt.Printf("x[%d] 类型为int, 内容为%d\n", index, value)
case string:
fmt.Printf("x[%d] 类型为string, 内容为%s\n", index, value)
case Student:
fmt.Printf("x[%d] 类型为Student, 内容为name = %s, id = %d\n", index, value.name, value.id)
}
}
}
结果:
x[0] 类型为int, 内容为1
x[1] 类型为string, 内容为hello go
x[2] 类型为Student, 内容为name = wielun, id = 123
二、异常处理
1、 error接口
(1)error接口的使用
package main
import (
"errors"
"fmt"
)
func main() {
err1 := fmt.Errorf("%s", "this is normal err1")
fmt.Println("err1 = ", err1)
err2 := errors.New("this is normal err2")
fmt.Println("err2 = ", err2)
}
结果:
err1 = this is normal err1
err2 = this is normal err2
(2)error接口应用
package main
import (
"errors"
"fmt"
)
func MyDiv(a, b int) (result int, err error) {
if b == 0 {
err = errors.New("分母不能为0")
return
} else {
result = a / b
}
return
}
func main() {
result, err := MyDiv(10, 0)
if err != nil {
fmt.Println("err = ", err)
} else {
fmt.Println("result = ", result)
}
}
结果:
err = 分母不能为0
2、panic
(1)显式调用panic函数
package main
import "fmt"
func testa() {
fmt.Println("aaaaaaaaa")
}
func testb() {
fmt.Println("bbbbbbbbb")
panic("this is a panic test")
}
func testc() {
fmt.Println("cccccccccccccc")
}
func main() {
testa()
testb()
testc()
}
结果:
aaaaaaaaa
bbbbbbbbb
panic: this is a panic test
goroutine 1 [running]:
main.testb(...)
E:/MyWork/Go Projects/src/wielun666@163.com/05/03_显式调用pannic函数.go:11
main.main()
E:/MyWork/Go Projects/src/wielun666@163.com/05/03_显式调用pannic函数.go:20 +0xf5
exit status 2
(2)数组越界导致panic
package main
import "fmt"
func testa() {
fmt.Println("aaaaaaaaa")
}
func testb(x int) {
var a [10]int
a[x] = 111
}
func testc() {
fmt.Println("cccccccccccccc")
}
func main() {
testa()
testb(20)
testc()
}
结果:
aaaaaaaaa
panic: runtime error: index out of range [20] with length 10
goroutine 1 [running]:
main.testb(...)
E:/MyWork/Go Projects/src/wielun666@163.com/05/04_数组越界导致panic.go:11
main.main()
E:/MyWork/Go Projects/src/wielun666@163.com/05/04_数组越界导致panic.go:20 +0x8c
exit status 2
3、recover的使用
package main
import "fmt"
func testa() {
fmt.Println("aaaaaaaaa")
}
func testb(x int) {
// 设置recover
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
var a [10]int
a[x] = 111
}
func testc() {
fmt.Println("cccccccccccccc")
}
func main() {
testa()
testb(20)
testc()
}
结果:
aaaaaaaaa
runtime error: index out of range [20] with length 10
cccccccccccccc
下一篇文章
> Go入门(六)之文本文件处理