严格意义上讲, Go语言中没有类(class)的概念, 但是可以将结构体比作类, 因为在结构体中可以添加属性(成员)和方法(函数);
// 父类
type Persion struct {
id int
name string
age int
}
// 子类
type Student struct {
Persion // 继承属性 结构体嵌套
score int // 添加专属属性
}
func main() {
// 顺序初始化
var s1 Student = Student{Persion{101, "小明", 18}, 98}
fmt.Println(s1) // {{101 小明 18} 98}
// 自动推导类型
s2 := Student{Persion{102, "张三", 19}, 90}
fmt.Println(s2) // {{102 张三 19} 90}
// 指定初始化: 没有初始化的部分使用默认值
s3 := Student{score: 100}
fmt.Println(s3) // {{0 0} 100}
}
func main() {
var s1 Student = Student{Persion{101, "小明", 18}, 98}
// 成员操作 .
s1.score = 89
fmt.Println(s1) // {{101 小明 18} 89}
s1.Persion.id = 110
fmt.Println(s1) // {{110 小明 18} 89}
// 因为父类被继承, 所以不需要.父类
s1.age = 22
s1.Persion = Persion{100, "李四", 20}
fmt.Println(s1) // {{100 李四 20} 89}
}
子类与父类结构体有相同的成员名时, 默认赋值给子类, 采用就近原则
type Stu struct {
Persion
name string
score int
}
func main() {
var s3 Stu
s3.name = "王五"
fmt.Println(s3) // {{0 0} 王五 0}
s3.Persion.name = "wangwu"
fmt.Println(s3) // {{0 wangwu 0} 王五 0}
}
// 指针类型的匿名字段
// 子类
type Student3 struct {
*Persion
score int
}
func main() {
var s Student3
s.score = 90
fmt.Println(s) // { 90}
// s.id = 100 // err: 内存地址指向为空
s.Persion = new(Persion)
s.name = "赵六"
s.id = 103
fmt.Println(s) // {0xc00000c060 90}
fmt.Println(s.id, s.name, s.score) // 103 赵六 90
(*s.Persion).name = "周杰伦"
fmt.Println(s.id, s.name, s.score) // 103 周杰伦 90
s.Persion = &Persion{105, "林俊杰", 35}
fmt.Println(s.id, s.name, s.score) // 105 林俊杰 90
}
type Father struct {
name string
age int
sex string
}
type Monther struct {
id int
addr string
}
type Son struct {
Father
Monther
score int
}
func main() {
var son Son
son.id = 200
son.addr = "北京"
son.name = "张三"
son.age = 18
son.sex = "男"
son.score = 100
fmt.Println(son) // {{张三 18 男} {200 北京} 100}
// 自动推导
s1 := Son{Father{"李四", 20, "女"}, Monther{201, "上海"}, 90} // {{李四 20 女} {201 上海} 90}
fmt.Println(s1)
}
type Humen struct {
id int
name string
}
type Persion struct {
Humen
age int
sex string
}
type Student struct {
Persion
score int
}
func main() {
// 初始化
var stu Student
stu.name = "张三"
stu.age = 20
stu.score = 94
fmt.Println(stu) // {{{0 张三} 20 } 94}
// 自动推导
stu1 := Student{Persion{Humen{100, "李四"}, 30, "男"}, 98}
fmt.Println(stu1) // {{{100 李四} 30 男} 98}
}
语法:
// 定义方法
func (对象名 类型)方法名(参数列表) {
方法体
}
type Cat struct {
name string
age int
}
// 定义方法需要绑定对象
func (c Cat) show() {
fmt.Println(c.name + "喵喵叫...")
}
type Dog struct {
name string
age int
}
func (d Dog) show() {
fmt.Println("汪汪叫...")
}
func main() {
var c Cat
c.name = "气气"
c.age = 2
// 调用对象方法
c.show() // 气气喵喵叫...
}
type Student struct {
id int
name string
age int
score int
}
func (s Student) Display() {
s.name = "张三"
fmt.Println(s) // {101 张三 30 -5}
}
// 对象不同, 方法名相同, 不会冲突
// 在方法调用中, 方法接收者是指针类型
// 指针类型、普通类型 表示的是相同对象的类型
func (s *Student) change(age int) {
s.age = age
}
func main() {
stu := Student{101, "亚索", 30, -5}
stu.Display()
fmt.Println(stu) // {101 亚索 30 -5}
stu.change(18)
fmt.Println(stu) // {101 亚索 18 -5}
}
type Person struct {
id int
name string
age int
}
type Student struct {
Person
class int // 班级
}
func (p *Person) PrintInfo() {
fmt.Printf("编号: %d\n", p.id)
fmt.Printf("姓名: %s\n", p.name)
fmt.Printf("年龄: %d\n", p.age)
}
func main() {
p := Person{110, "张三", 18}
p.PrintInfo()
// 编号: 110
// 姓名: 张三
// 年龄: 18
s := Student{Person{111, "李四", 20}, 2}
// 子类可以继承父类的属性和方法
s.PrintInfo()
// 编号: 111
// 姓名: 李四
// 年龄: 20
}
方法重写之后使用的是子类的方法
package main
import "fmt"
// 定义接口: 一般以er结尾, 根据接口实现功能
type Humaner interface {
// 方法:仅仅是方法的声明
sayhi()
}
type Student struct {
name string
age int
score int
}
func (s *Student) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我的成绩是%d分\n", s.name, s.age, s.score)
}
type Teacher struct {
name string
age int
subject string
}
func (t *Teacher) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我教的科目是%s\n", t.name, t.age, t.subject)
}
func main() {
// 定义一个接口变量
// 接口是一种数据类型, 可以接受满足对象的信息
// 接口是虚的, 方法是实的
// 接口定义规则, 方法实现规则
// 接口中定义的规则, 对象中必须有实现
var h Humaner
// 创建对象
stu := Student{"小明", 18, 98}
// stu.sayhi() // 我是小明, 今年18岁, 我的成绩是98分
// 将对象信息赋值给接口类型变量
h = &stu
h.sayhi() // 我是小明, 今年18岁, 我的成绩是98分
tea := Teacher{"老王", 30, "物理"}
// tea.sayhi() // 我是老王, 今年30岁, 我教的科目是物理
h = &tea
h.sayhi()
}
package main
import "fmt"
type Humaner interface {
sayhi()
}
type Student struct {
name string
age int
score int
}
func (s *Student) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我的成绩是%d分\n", s.name, s.age, s.score)
}
type Teacher struct {
name string
age int
subject string
}
func (t *Teacher) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我教的科目是%s\n", t.name, t.age, t.subject)
}
// 多态的实现
// 将接口作为函数参数, 实现多态
func sayhello(h Humaner) {
h.sayhi()
}
func main() {
stu := Student{"小明", 18, 98}
// 调用多态
sayhello(&stu) // 我是小明, 今年18岁, 我的成绩是98分
tea := Teacher{"老王", 30, "物理"}
// 调用多态
sayhello(&tea) // 我是老王, 今年30岁, 我教的科目是物理
}
package main
import "fmt"
type Humaner interface {
sayhi()
}
type Personer interface { // 超集
Humaner // 匿名字段
sing(string)
}
type Student struct {
name string
age int
score int
}
func (s *Student) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我的成绩是%d分\n", s.name, s.age, s.score)
}
func (s *Student) sing(n string) {
fmt.Printf("我是%s, 我为大家唱首歌: %s\n", s.name, n)
}
type Teacher struct {
name string
age int
subject string
}
func (t *Teacher) sayhi() {
fmt.Printf("我是%s, 今年%d岁, 我教的科目是%s\n", t.name, t.age, t.subject)
}
func (t *Teacher) sing(n string) {
fmt.Printf("我是%s, 我为大家唱首歌: %s\n", t.name, n)
}
func main0901() {
// 定义接口
var h Humaner
stu := Student{"小明", 18, 98}
h = &stu
h.sayhi() // 我是小明, 今年18岁, 我的成绩是98分
// 定义接口变量
var p Personer
p = &stu
p.sing("小星星") // 我是小明, 我为大家唱首歌: 小星星
// tea := Teacher{"老王", 30, "物理"}
}
func main() {
// 接口的转换
// 接口类型变量定义
var h Humaner // 子集
var p Personer // 超集
var stu Student = Student{"小吴", 18, 59}
p = &stu
// 将一个接口赋值给另一个接口
// 超集中包含所有子集的方法
h = p // ok
h.sayhi() // 我是小吴, 今年18岁, 我的成绩是59分
}
func main() {
var i interface{}
// 接口类型
fmt.Println(i) //
fmt.Printf("%T\n", i) //
i = 10
fmt.Println(i) // 10
fmt.Printf("%T\n", i) // int
i = 3.14
fmt.Println(i) // 3.14
fmt.Printf("%T\n", i) // float64
}
接收任意类型的数据
func test() {
fmt.Println("test...")
}
func main() {
// 定义空接口类型的切片
var i []interface{}
fmt.Printf("%T\n", i)
i = append(i, 10, 3.14, "aaa", test)
fmt.Println(i) // [10 3.14 aaa 0x109eb30]
for idx := 0; idx < len(i); idx++ {
fmt.Println(i[idx])
// 10
// 3.14
// aaa
// 0x109eb30
}
}
interface的变量里面可以存储任意类型的数值. 那么如何反向知道这个变量里面实际保存了哪个类型的对象呢:
Go语言里面有一个语法, 可以直接判断是否是该类型的变量: value, ok = element.(T), 这里value就是变量的值, ok是一个bool类型, element是interface变量, T是断言的类型;
如果element里面确实是存储了T类型的数值, 那么OK返回true, 否则返回false;
func demo() {
fmt.Println("hello...")
}
func main() {
// 类型断言
var i []interface{}
i = append(i, 10, 3.14, "aaa", demo)
fmt.Println(i) // // [10 3.14 aaa 0x109cfb0]
for _, v := range i {
fmt.Println(v)
if data, ok := v.(int); ok {
fmt.Println("整型数据", data)
} else if data, ok := v.(float64); ok {
fmt.Println("浮点数据", data)
} else if data, ok := v.(string); ok {
fmt.Println("字符串数据", data)
} else if data, ok := v.(func()); ok {
// 函数调用
data()
}
// 10
// 整型数据 10
// 3.14
// 浮点数据 3.14
// aaa
// 字符串数据 aaa
// 0x109cfb0
// hello...
}
}
func main() {
var i []interface{}
i = append(i, 10, 3.14, "aaa", demo)
for _, data := range i {
switch value := data.(type) {
case int:
fmt.Println("整型数据", value)
case float64:
fmt.Println("浮点型数据", value)
case string:
fmt.Println("字符串数据", value)
case func():
value()
default:
fmt.Println("类型未知...", value)
}
}
// 整型数据 10
// 浮点型数据 3.14
// 字符串数据 aaa
// hello...
}