【go语言 | 第3篇】go中类的封装、继承、多态 + 反射

文章目录

  • [golang 中类的封装](#golang 中类的封装)
  • 类的继承
  • 类的多态
  • [interface{} 万能数据类型](#interface{} 万能数据类型)
  • 反射
    • [1. 变量内置 pair 结构](#1. 变量内置 pair 结构)
    • [2. 反射 reflect 机制](#2. 反射 reflect 机制)
    • [3. 结构体标签](#3. 结构体标签)
    • [4. 结构体标签在 Json 中的应用](#4. 结构体标签在 Json 中的应用)

golang 中类的封装

java 复制代码
package main

import "fmt"

// 类名首字母大写,表示其他包也可以访问
type Person struct {
	Name string   // 属性名首字母大写,表示该属性对外能够访问,否则只能类的内部访问
	Age int
	Sex string
}

func (this *Person) Show() {
	fmt.Println("姓名:", this.Name, ",年龄:", this.Age, ",性别:", this.Sex)
}

func (this *Person) GetName() string {
	return this.Name
}

func (this *Person) SetName(name string) {
	// this是调用方法对象(指针)
	this.Name = name
}

func (this Person) SetName2(name string) {
	// this是调用方法对象的一个副本
	this.Name = name
}
func main() {
	p := Person {
		Name: "张三",
		Age: 18,
		Sex: "男",
	}

	p.Show()

	fmt.Println("==============================================")
	p.SetName2("honghong")
	p.Show()

	fmt.Println("==============================================")
	p.SetName("honghong")
	p.Show()

}

注意:go 语言中,类名、属性、方法的首字母是否大写,都与其是否能被外部(其它包)访问有关,否则只能在本包内访问。

类的继承

go 复制代码
package main

import "fmt"

type Human struct {
	name string
	sex string
}

func (this *Human) Eat() {
	fmt.Println("Human Eating...")
}

func (this *Human) Walk() {
	fmt.Println("Human Walking...")
}

// ===========================
// 继承:定义 SuperMan 继承自 Human
type SuperMan struct {
	// 表示继承自Human
	Human
	level int
}

// 重写 eat 方法
func (this *SuperMan) Eat() {
	fmt.Println("SuperMan Eating...============")
}

// 增加 Fly 方法
func (this *SuperMan) Fly() {
	fmt.Println("SuperMan Flying...============")
}

func main() {
	h := Human {"zhangsan", "male"}
	h.Eat()
	h.Walk()

	fmt.Println("============================================================")

	// 定义子类对象
	//s := SuperMan {Human{"lisi", "female"}, 2}
	var s SuperMan
	s.name = "lisi"
	s.sex = "female"
	s.level = 2	

	s.Eat()  
	s.Walk()
	s.Fly()
}

类的多态

go 复制代码
package main

import "fmt"

// interface
type Animal interface {
	Sleep()
	GetColor() string
	GetType() string
}

// 具体的类
type Cat struct {
	Color string
}

func (this *Cat) Sleep() {
	fmt.Println("Cat is sleeping")
}

func (this *Cat) GetColor() string {
	return this.Color
}

func (this *Cat) GetType() string {
	return "Cat"
}

// 具体的类
type Dog struct {
	Color string
}

func (this *Dog) Sleep() {
	fmt.Println("Dog is sleeping")
}

func (this *Dog) GetColor() string {
	return this.Color
}

func (this *Dog) GetType() string {
	return "Dog"
}

func showAnimal (animal Animal) {
	fmt.Println(animal.GetType(), animal.GetColor())
}

func main() {
	// 多态体现:同一个接口类型的变量,可以指向不同的实现类对象
	var animal Animal
	animal = &Cat{"white"}
	animal.Sleep()

	animal = &Dog{"black"}
	animal.Sleep()

	fmt.Println("==============================================")

	// 多态体现:
	cat := Cat{"white"}	
	dog := Dog{"black"}
	showAnimal(&cat)
	showAnimal(&dog)

}

多态的要素:

  1. 有一个接口
  2. 子类要实现接口的所有接口方法,少一个都不行
  3. 父类的引用指向子类的具体数据类型

interface{} 万能数据类型

interface{} 空接口:

  1. int、string、float64... 均实现了 interface{}
  2. 可以用 interface{} 类型代表任何数据类型

interface 用于类型断言

go 复制代码
package main

import "fmt"

// interface{} 作为万能数据类型
func myFun(args interface{}) {
	fmt.Println("myFun!")
	fmt.Println(args)

	// 提供 interface{} 类型断言
	value, ok := args.(string)
	if !ok {
		fmt.Println("args is not string")
	} else {
		fmt.Println("args is string")
		fmt.Println("value = ", value)
	}
}

func main() {
	myFun(11)
	fmt.Println("====================================")
	myFun("hello")
	fmt.Println("====================================")
	myFun(true)
	fmt.Println("====================================")
	myFun(1.234)
}

反射

1. 变量内置 pair 结构

反射是通过 pair 结构来得到 type。

2. 反射 reflect 机制

通过 reflect 包动态获取 type 和 value:

e.g.1

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

func PrintNum(arg interface{}) {
	fmt.Println("type is: ", reflect.TypeOf(arg))
	fmt.Println("value is: ", reflect.ValueOf(arg))
}
func main() {
	var num float64 = 1.235

	PrintNum(num)
}

e.g.2

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id int
	Name string
	Age int
}

func (this User) Call() {
	fmt.Println("user call...")
}

func main() {
	u := User{1, "honghong", 18}

	PrintFieldsAndValues(u)
}

func PrintFieldsAndValues(input interface{}) {
	// 获取 input 的type
	inputtype := reflect.TypeOf(input)
	fmt.Println("inputtype is: ", inputtype)
	// 获取 input 的value
	inputvalue := reflect.ValueOf(input)
	fmt.Println("inputvalue is: ", inputvalue)

	fmt.Println("==========================================================")
	// 通过 type 获取里面的字段
	// 1. interface获取 type,通过 type 获取 NumFields, 遍历字段
	// 2. 得到每个 field,数据类型
	// 3. 通过 field 有一个 Interface() 方法得到 value
	for i := 0; i < inputtype.NumField(); i++ {
		field := inputtype.Field(i)
		value := inputvalue.Field(i).Interface()

		fmt.Printf("%v: %s = %v\n", field.Type, field.Name, value)
	}

	fmt.Println("==========================================================")
	// 通过 type 获取方法
	for i := 0; i < inputtype.NumMethod(); i++ {
		method := inputtype.Method(i)
		fmt.Printf("%s: %v\n", method.Name, method.Type)
	}
}

3. 结构体标签

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

type resume struct {
	Name string `info:"name" doc:"我的名字"`
	sex string  `info:"sex" doc:"性别"`
}

func PrintTag(data interface{}) {
	t := reflect.TypeOf(data).Elem()

	for i := 0; i < t.NumField(); i++ {
		tagInfo := t.Field(i).Tag.Get("info")
		tagDoc := t.Field(i).Tag.Get("doc")

		fmt.Println("tag info:", tagInfo, "    tag doc:", tagDoc)
	}
}

func main() {
	var r resume

	PrintTag(&r)
}

4. 结构体标签在 Json 中的应用

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)


type Movie struct {
	Title string     `json:"title"`
	Year int		 `json:"year"`
	Price float64    `json:"rmb"`
	Actors []string  `json:"actors"`
}

func main() {
	movie := Movie {"唐顿庄园", 2000, 9.5, []string {"tom", "jerry", "lucy"}}

	// 编码 movie  结构体------------> json
	jsonStr, err := json.Marshal(movie)
	if err != nil {
		fmt.Println("json.Marshal err:", err)
		return
	}
	fmt.Printf("%s\n", jsonStr)

	// 解码 json ------------> movie 结构体
	myMovie := Movie{}
	err = json.Unmarshal(jsonStr, &myMovie)
	if err != nil {
		fmt.Println("json.Unmarshal err:", err)
		return
	}
	fmt.Printf("%v\n", myMovie)

}
相关推荐
李姆斯3 小时前
技术方案评审没人听?别人抓不住重点?你不妨这样做!
前端·后端·面试
毕设源码-钟学长4 小时前
【开题答辩全过程】以 基于springboot的健身房ERP系统设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
古城小栈4 小时前
rust 字符串,更严谨的设计
开发语言·rust
To Be Clean Coder4 小时前
【Spring源码】getBean源码实战(七)——BeanPostProcessor与初始化方法
java·后端·spring
汪小成4 小时前
Go CLI 入口设计:参数解析、错误处理与项目分层实战
后端·go
+VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue民宿平台管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
xl.liu5 小时前
GN(Girvan-Newman)算法详解:从原理到实现及其在商品关联集合分析中的应用
开发语言·算法·php
hoiii1875 小时前
基于MATLAB/Simulink使用M函数实现无刷直流电机(BLDCM)双闭环控制系统
开发语言·matlab
superman超哥5 小时前
Rust 复制语义(Copy Trait)与移动语义的区别:类型系统的精确控制
开发语言·后端·rust·编程语言·移动语义·rust复制语义·copy trait
怒放吧德德6 小时前
RocketMQ从实战到源码:初识RocketMQ
java·后端·rocketmq