Go语言基础
介绍
基础
介绍
- 本文介绍Go语言中面向对象(封装、继承、多态)相关特性、反射(Type、Value、动态创建结构体)相关特性、等相关知识。
基础
面向对象
- Go语言是否是一门面向对象的语言,Golang 官方答案是:YES OR NO。
- Go语言从设计和语法上本身是一门面向过程、支持并发的语言,没有类、继承和多态的特性。
- Go语言提供了部分面向对象的特性、可以实现类似面向对象程序设计。
封装
- 封装就是隐藏实现细节,将数据和方法使用语法规则约束(类似private),外部对象无法直接访问数据字段,只能通过所提供的方法进行操作。在面向对象语言中,封装是类 class 提供的特性。
- Go语言没有类的概念,但提供了结构体的定义,可以将属性字段定义在结构体中,通过实例化结构体对象来访问字段。结构体中不能定义方法,都在类外定义。
- Go语言中,通过变量名或方法名首字母的大小写来实现类似public和private功能,但在同一个包中,不管首大写或小写都在包内可见,所以在Go语言中,对封装的约束是在包级别的约束,同一个包内无访问限制。
// 包 pkgtest 内容,文件名称 pkgtest.go
package pkgtest
import "fmt"
// 结构体及所有字段外部可直接访问
type NetAddr struct {
Ip string
Port int
}
// 结构体外部可直接访问,字段外部不可访问
type NetAddrs struct {
ip string
port int
}
// 提供外部直接访问的方法
func (c *NetAddrs) SetAddrPort(ip string, port int) {
c.ip = ip
c.port = port
}
// 自定义结构体打印信息
func (c *NetAddrs) String() string {
return fmt.Sprintf("ip: %#v, port: %#v", c.ip, c.port)
}
// main 包 main.go 文件
package main
import (
"fmt"
"pkgtest"
)
func main() {
a := pkgtest.NetAddr{"127.0.0.1", 9080}
fmt.Printf("a = ip: %#v, port: %#v\n", a.Ip, a.Port)
var b pkgtest.NetAddrs
fmt.Println("b = ", &b)
b.SetAddrPort("127.0.0.1", 9090)
fmt.Println("b = ", &b)
}
输出结果
a = ip: “127.0.0.1”, port: 9080
b = ip: “”, port: 0
b = ip: “127.0.0.1”, port: 9090
继承
- 继承可以提高程序代码复用性,将多个结构体所存在的相同的属性字段和方法提取出来,抽象出一个新的结构体作为基类,其它派生类去继承此类的特性,并且可以扩展自有属性和方法。
- Go语言中没有继承的概念,通过匿名结构体嵌套来实现继承的效果,与真正的继承存在一些区别。
- Go语言支持多继承,即在结构体中嵌套多个匿名结构体。
- 通过嵌入结构体类型实现代码复用和扩展性并不是完全等同于传统面向对象语言中的继承关系。
package main
import "fmt"
type Animal struct {
name string
}
// 基类方法
func (c Animal) GetName() string {
return fmt.Sprintf("name: %#v", c.name)
}
type Cat struct {
Animal // 继承Animal
id int
}
// 派生类独有方法
func (c Cat) Voice() {
fmt.Println("id: ", c.id, ", cat ~~~~~~")
}
func main() {
ani := Animal{"animal"}
fmt.Println(ani, ", ", ani.GetName())
cat := &Cat{Animal{"maomao"}, 10010}
fmt.Println(cat)
fmt.Println(cat.GetName())
cat.Voice()
}
输出结果
{animal} , name: “animal”
&{{maomao} 10010}
name: “maomao”
id: 10010 , cat ~~~~~~
- 重写基类方法。
package main
import "fmt"
type Animal struct {
name string
}
// 基类方法
func (c Animal) GetName() string {
return fmt.Sprintf("Animal name: %#v", c.name)
}
type Cat struct {
Animal // 继承Animal
}
// 派生类重新基类方法
func (c Cat) GetName() string {
return fmt.Sprintf("Cat name: %#v", c.name)
}
func main() {
ani := Animal{"animal"}
fmt.Println(ani, ", ", ani.GetName())
cat := Cat{Animal{"cat"}}
fmt.Println(cat, ", ", cat.GetName())
}
输出结果
{animal} , Animal name: “animal”
{{cat}} , Cat name: “cat”
多态
- 多态是指一个对象可以具有多种不同的形态或表现形式,也就是同一个方法在不同的对象实例中,行为不同。
- Go 语言中,没有传统的类和继承的概念,多态性通常使用接口(interface)来实现,由于接口可以引用不同类型的对象,所以通过接口类型可以实现多态。
package main
import "fmt"
// 定义接口
type Animal interface {
Eat()
}
// 接口实现
type Cat struct {
}
func (c Cat) Eat() {
fmt.Println("cat eat")
}
type Dog struct {
}
func (c Dog) Eat() {
fmt.Println("dog eat")
}
// 提供统一接口调用函数
func Invork(a Animal) {
a.Eat()
}
func main() {
// 声明接口变量,接收不同的的对象
var a Animal = Cat{}
Invork(a)
a = Dog{}
Invork(a)
}
输出结果
cat eat
dog eat
反射
- 反射是指在程序运行时,可以动态的访问和修改任意类型对象的结构和成员。
- Go 语言中提供 reflect 包提供反射的功能,对于每一个变量都有:Type 和Value 两个属性。
- 反射三原则:从接口值到反射对象的反射(Reflection goes from interface value toreflection object);从反射对象到接口值的反射(Reflection goes from reflection object to interface value);为了修改反射对象,其值必须可设置(To modify a reflectionobject, the value must be settable)。
Type
- reflect.Type 是一个接口类型,用于获取变量类型信息,可通过 reflect.TypeOf 函数获取某个变量的类型信息,通过 reflect.ValueOf 函数获取某个变量的值。
package main
import (
"fmt"
"reflect"
)
func main() {
// 定义不同类型的变量
a := 10
b := "strings"
fmt.Printf("a type: %v, b type: %v\n", reflect.TypeOf(a), reflect.TypeOf(b))
fmt.Printf("a value: %v, b value: %v\n", reflect.ValueOf(a), reflect.ValueOf(b))
}
输出结果
a type: int, b type: string
a value: 10, b value: strings
- reflect.Type 可以通过命令 go doc reflect.Type 查看其接口定义。
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
Implements(u Type) bool
AssignableTo(u Type) bool
ConvertibleTo(u Type) bool
Comparable() bool
Bits() int
ChanDir() ChanDir
IsVariadic() bool
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
In(i int) Type
Key() Type
Len() int
NumField() int
NumIn() int
NumOut() int
Out(i int) Type
}
- 反射获取结构体详细信息。
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type Cpu struct {
name string
id int
}
func (c Cpu) CpuInfo() {
fmt.Println("name: ", c.name, ", id: ", c.id)
}
// 继承
type Intel struct {
Cpu
}
// 组合
type AMD struct {
cpu Cpu
level float32
}
// 声明函数
func TestFunc(i int, s string) error {
i = 10
s = "str"
return nil
}
func main() {
// 声明结构体变量,打印类型
cpu := Cpu{"CPU", 10000}
fmt.Printf("cpu type: %v, kind: %v\n", reflect.TypeOf(cpu), reflect.TypeOf(cpu).Kind())
intel := &Intel{Cpu{"INTEL", 10001}}
fmt.Printf("intel type: %v, kind: %v\n", reflect.TypeOf(intel), reflect.TypeOf(intel).Kind())
amd := AMD{Cpu{"AMD", 10002}, 12.35}
fmt.Printf("amd type: %v, kind: %v\n", reflect.TypeOf(amd), reflect.TypeOf(amd).Kind())
fmt.Println("====================================")
// 打印属性字段与方法数量
fmt.Printf("cpu field size: %v, method size: %v\n", reflect.TypeOf(cpu).NumField(), reflect.TypeOf(cpu).NumMethod())
fmt.Printf("intel field size: %v, method size: %v\n", reflect.TypeOf(intel).Elem().NumField(), reflect.TypeOf(intel).NumMethod())
fmt.Printf("amd field size: %v, method size: %v\n", reflect.TypeOf(amd).NumField(), reflect.TypeOf(amd).NumMethod())
fmt.Println("====================================")
// 遍历获取属性字段信息
for i := 0; i < reflect.TypeOf(amd).NumField(); i++ {
fmt.Printf("%v\t", reflect.TypeOf(amd).Field(i))
}
fmt.Println()
fmt.Println("====================================")
// 通过属性字段索引获取信息
fmt.Println(reflect.TypeOf(amd).FieldByIndex([]int{1})) // level float32
fmt.Println(reflect.TypeOf(amd).FieldByIndex([]int{0, 1})) // id int
fmt.Println("====================================")
// 遍历获取方法信息
for i := 0; i < reflect.TypeOf(intel).NumMethod(); i++ {
n := reflect.TypeOf(intel).Method(i)
fmt.Printf("Name: %v, Kind: %v, InputSize: %v, OutputSize: %v, Info: %v\t", n.Name, n.Type.Kind(), n.Type.NumIn(), n.Type.NumOut(), n)
for i := 0; i < n.Type.NumIn(); i++ {
fmt.Printf("第 %d 个输入参数类型: %s \n", i, n.Type.In(i))
}
for i := 0; i < n.Type.NumOut(); i++ {
fmt.Printf("第 %d 个输出参数类型: %s \n", i, n.Type.Out(i))
}
}
fmt.Println()
fmt.Println("====================================")
// 获取函数详细信息
m := reflect.TypeOf(TestFunc)
fmt.Printf("m Name: %v, Kind: %v, InputSize: %v, OutputSize: %v\n", m.Name(), m.Kind(), m.NumIn(), m.NumOut())
for i := 0; i < m.NumIn(); i++ {
fmt.Printf("第 %d 个输入参数类型: %s \n", i, m.In(i))
}
for i := 0; i < m.NumOut(); i++ {
fmt.Printf("第 %d 个输出参数类型: %s \n", i, m.Out(i))
}
}
输出结果
cpu type: main.Cpu, kind: struct
intel type: *main.Intel, kind: ptr
amd type: main.AMD, kind: struct
====================================
cpu field size: 2, method size: 1
intel field size: 1, method size: 1
amd field size: 2, method size: 0
====================================
{cpu main main.Cpu 0 [0] false} {level main float32 24 > [1] false}
====================================
{level main float32 24 [1] false}
{id main int 16 [1] false}
====================================
Name: CpuInfo, Kind: func, InputSize: 1, OutputSize: 0, Info: > {CpuInfo func(*main.Intel) <func(*main.Intel) Value> 0} 第 0 个> 输入参数类型: *main.Intel
====================================
m Name: , Kind: func, InputSize: 2, OutputSize: 1
第 0 个输入参数类型: int
第 1 个输入参数类型: string
第 0 个输出参数类型: error
Value
- 使用 reflect.ValueOf 获取存储的具体值。
- 使用指令 go doc reflect.Value 查看方法。
func Append(s Value, x ...Value) Value
func AppendSlice(s, t Value) Value
func Indirect(v Value) Value
func MakeChan(typ Type, buffer int) Value
func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value
func MakeMap(typ Type) Value
func MakeMapWithSize(typ Type, n int) Value
func MakeSlice(typ Type, len, cap int) Value
func New(typ Type) Value
func NewAt(typ Type, p unsafe.Pointer) Value
func ValueOf(i any) Value
func Zero(typ Type) Value
func (v Value) Addr() Value
func (v Value) Bool() bool
func (v Value) Bytes() []byte
func (v Value) Call(in []Value) []Value
func (v Value) CallSlice(in []Value) []Value
func (v Value) CanAddr() bool
func (v Value) CanComplex() bool
func (v Value) CanConvert(t Type) bool
func (v Value) CanFloat() bool
func (v Value) CanInt() bool
func (v Value) CanInterface() bool
func (v Value) CanSet() bool
func (v Value) CanUint() bool
func (v Value) Cap() int
func (v Value) Clear()
func (v Value) Close()
func (v Value) Comparable() bool
func (v Value) Complex() complex128
func (v Value) Convert(t Type) Value
func (v Value) Elem() Value
func (v Value) Equal(u Value) bool
func (v Value) Field(i int) Value
func (v Value) FieldByIndex(index []int) Value
func (v Value) FieldByIndexErr(index []int) (Value, error)
func (v Value) FieldByName(name string) Value
func (v Value) FieldByNameFunc(match func(string) bool) Value
func (v Value) Float() float64
func (v Value) Grow(n int)
func (v Value) Index(i int) Value
func (v Value) Int() int64
func (v Value) Interface() (i any)
func (v Value) InterfaceData() [2]uintptr
func (v Value) IsNil() bool
func (v Value) IsValid() bool
func (v Value) IsZero() bool
func (v Value) Kind() Kind
func (v Value) Len() int
func (v Value) MapIndex(key Value) Value
func (v Value) MapKeys() []Value
func (v Value) MapRange() *MapIter
func (v Value) Method(i int) Value
func (v Value) MethodByName(name string) Value
func (v Value) NumField() int
func (v Value) NumMethod() int
func (v Value) OverflowComplex(x complex128) bool
func (v Value) OverflowFloat(x float64) bool
func (v Value) OverflowInt(x int64) bool
func (v Value) OverflowUint(x uint64) bool
func (v Value) Pointer() uintptr
func (v Value) Recv() (x Value, ok bool)
func (v Value) Send(x Value)
func (v Value) Set(x Value)
func (v Value) SetBool(x bool)
func (v Value) SetBytes(x []byte)
func (v Value) SetCap(n int)
func (v Value) SetComplex(x complex128)
func (v Value) SetFloat(x float64)
func (v Value) SetInt(x int64)
func (v Value) SetIterKey(iter *MapIter)
func (v Value) SetIterValue(iter *MapIter)
func (v Value) SetLen(n int)
func (v Value) SetMapIndex(key, elem Value)
func (v Value) SetPointer(x unsafe.Pointer)
func (v Value) SetString(x string)
func (v Value) SetUint(x uint64)
func (v Value) SetZero()
func (v Value) Slice(i, j int) Value
func (v Value) Slice3(i, j, k int) Value
func (v Value) String() string
func (v Value) TryRecv() (x Value, ok bool)
func (v Value) TrySend(x Value) bool
func (v Value) Type() Type
func (v Value) Uint() uint64
func (v Value) UnsafeAddr() uintptr
func (v Value) UnsafePointer() unsafe.Pointer
- 通过 reflect.ValueOf() 获取值。
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type Cpu struct {
name string
id int
}
func (c Cpu) CpuInfo() {
fmt.Println("name: ", c.name, ", id: ", c.id)
}
// 继承
type Intel struct {
Cpu
}
// 组合
type AMD struct {
cpu Cpu
level float32
}
func main() {
// 声明结构体变量,打印类型fmt.Printf("cpu type: %v, kind: %v\n", reflect.TypeOf(cpu), reflect.TypeOf(cpu).Kind())
intel := &Intel{Cpu{"INTEL", 10001}}
amd := AMD{Cpu{"AMD", 10002}, 12.35}
ri := reflect.ValueOf(intel)
ra := reflect.ValueOf(amd)
fmt.Println("intel value: ", ri)
fmt.Println("amd value: ", ra)
}
输出结果
intel value: &{{INTEL 10001}}
amd value: {{AMD 10002} 12.35}
- reflect.Type、reflect.Value类型与变量之间的转换。
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type Cpu struct {
name string
id int
}
func (c Cpu) CpuInfo() {
fmt.Println("name: ", c.name, ", id: ", c.id)
}
func Convert(v any) { // 使用 any 接收任意类型的反射变量
val := reflect.ValueOf(v) // 将 any 类型转成 reflect.Value 类型
fmt.Println("val: ", val)
inter := val.Interface() // 将 reflect.Value 类型转成 any 类型
switch v.(type) { // 将 any 类型转换为原始变量类型
case Cpu:
cpu := inter.(Cpu)
fmt.Printf("原类型为 %T\n", cpu)
case *Cpu:
cpu := inter.(*Cpu)
fmt.Printf("原类型为 %T\n", cpu)
}
}
func main() {
// 声明指针变量、普通变量
pcpu := &Cpu{"INTEL", 10001}
cpu := Cpu{"AMD", 10002}
// 执行转换函数
Convert(pcpu)
Convert(cpu)
}
输出结果
val: &{INTEL 10001}
原类型为 *main.Cpu
val: {AMD 10002}
原类型为 main.Cpu
- 修改变量值,变量可修改的条件:对于基本数据类型变量可获取地址;对于结构体属性必须是可获取地址且字段属性为public(公开的)。
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type Cpu struct {
Name string
Id int
}
func (c Cpu) CpuInfo() {
fmt.Println("名称: ", c.Name, ", 编号: ", c.Id)
}
// 修改字段值
func SetValue(val reflect.Value) {
fmt.Println("kind: ", val.Kind())
switch val.Kind() {
// 此处只处理指针与结构体
case reflect.Ptr, reflect.Struct:
for i := 0; i < val.NumField(); i++ {
kd := val.Field(i)
switch kd.Kind() { // 判断结构体字段类型
case reflect.String:
if kd.CanSet() { // 判断字段值可以设置(改变)
kd.SetString("change " + kd.String())
}
case reflect.Int:
if kd.CanSet() {
kd.SetInt(kd.Int() + 10)
}
}
}
}
}
func Convert(v any) { // 使用 any 接收任意类型的反射变量
val := reflect.ValueOf(v) // 将 any 类型转成 reflect.Value 类型
fmt.Println("val: ", val)
inter := val.Interface() // 将 reflect.Value 类型转成 any 类型
switch v.(type) { // 判断传入变量原始类型
case Cpu: // 结构体对象
cpu := inter.(Cpu)
fmt.Printf("原类型为 %T\n", cpu)
SetValue(val)
fmt.Println("convert cpu: ", val)
case *Cpu: // 结构体指针
cpu := inter.(*Cpu)
fmt.Printf("原类型为 %T\n", cpu)
SetValue(val.Elem())
fmt.Println("convert cpu: ", val)
}
}
func main() {
// 声明指针变量、普通变量
pcpu := &Cpu{"INTEL", 10001}
cpu := Cpu{"AMD", 10002}
// 打印原始结构体值
fmt.Println("pcpu: ", pcpu)
fmt.Println("cpu: ", cpu)
// 执行转换函数
Convert(pcpu) // 指针传参
Convert(cpu) // 值传参
// 打印转换后的结构体值
fmt.Println("pcpu: ", pcpu)
fmt.Println("cpu: ", cpu)
}
pcpu: &{INTEL 10001}
cpu: {AMD 10002}
val: &{INTEL 10001}
原类型为 *main.Cpu
kind: struct
convert cpu: &{change INTEL 10011}
val: {AMD 10002}
原类型为 main.Cpu
kind: struct
convert cpu: {AMD 10002}
pcpu: &{change INTEL 10011}
cpu: {AMD 10002}
- 通过反射调用结构体方法和函数。
package main
import (
"fmt"
"reflect"
)
// 定义结构体
type Cpu struct {
Name string
Id int
}
func (c *Cpu) CpuInfo() {
fmt.Println("名称: ", c.Name, ", 编号: ", c.Id)
}
func (c *Cpu) SetInfo(name string, id int) error {
c.Name = name
c.Id = id
fmt.Println("设置名称和编号")
return nil
}
func Test(a, b int) int {
return a + b
}
func main() {
// 声明变量
cpu := &Cpu{"AMD", 10002}
fmt.Println("cpu: ", cpu)
cr := reflect.ValueOf(cpu)
cr.MethodByName("CpuInfo").Call(nil)
cr.MethodByName("SetInfo").Call([]reflect.Value{reflect.ValueOf("Intel"), reflect.ValueOf(10001)})
cr.MethodByName("CpuInfo").Call(nil)
}
输出结果
cpu: &{AMD 10002}
名称: AMD , 编号: 10002
设置名称和编号
名称: Intel , 编号: 10001
动态创建结构体
- 通过反射特性,可动态创建结构体。
package main
import (
"fmt"
"reflect"
)
func main() {
cpu := []reflect.StructField{
{
Name: "Name",
Type: reflect.TypeOf(""),
},
{
Name: "Id",
Type: reflect.TypeOf(int(0)),
},
}
fmt.Printf("cpu type: %T, value: %v\n", cpu, cpu)
StructType := reflect.StructOf(cpu)
fmt.Printf("StructType type: %T, value: %v\n", StructType, StructType)
var s1 reflect.Value = reflect.ValueOf(StructType)
fmt.Printf("s1 type: %T, value: %v\n", s1, s1)
s := reflect.New(StructType).Elem()
fmt.Printf("s type: %T, value: %v\n", s, s)
s.Field(0).SetString("Intel")
s.Field(1).Set(reflect.ValueOf(10001))
fmt.Printf("s type: %T, value: %v\n", s, s)
}
输出结果
cpu type: []reflect.StructField, value: [{Name string 0 [] false} {Id int 0 [] false}]
StructType type: *reflect.rtype, value: struct { Name string; Id int }
s1 type: reflect.Value, value: struct { Name string; Id int }
s type: reflect.Value, value: { 0}
s type: reflect.Value, value: {Intel 10001}