Go|Go 基础知识三
方法method
【Go|Go 基础知识三】Go 中虽没有class,但依旧有method
通过显示说明receiver来实现与某个类型的组合
只能为同一个包中的类型定义方法
Receiver 可以是类型的值或者指针
不存在方法重载
可以使用值或指针来调用方法,编译器会自动完成转换
从某种意义上来说,方法是函数的语法糖,因为receiver其实就是
方法所接收的第1个参数(Method Value vs. Method Expression)
如果外部结构和嵌入结构存在同名方法,则优先调用外部结构的方法
类型别名不会拥有底层类型所附带的方法
方法可以调用结构中的非公开字段
package mainimport (
"fmt"
)type A struct {
Name string
}
type B struct {
Name string
}func main() {
a := A{}
a.Print()
fmt.Println(a.Name)b := B{}
b.Print()
fmt.Println(b.Name)
}//绑定A结构,定义Print方法
//* 通过指针来操作Name
func (a *A) Print() {
a.Name = "AA"
fmt.Println("A")
}//绑定B结构,定义Print方法func (b B) Print() {
b.Name = "BB"
fmt.Println("B")
}
文章图片
底层结构,如int型也可以添加方法
type TZ intfunc main() {
var a TZ
a.Pring()
//另外一种调用的方法
(*TZ).Pring(&a)}func (a *TZ) Pring() {
fmt.Println("TZ")
}
文章图片
对同一个package来说,方法的公有和私有都不重要,首字母大写是公有方法,首字母小写是私有方法。示例
根据为结构增加方法的知识,尝试声明一个底层类型为int的类型,如:a:=0,调用a.Increase()之后,a从0变成100。
并实现调用某个方法就递增100。
//定义TZ为底层int类型
type TZ intfunc main() {
var a TZ
a.Increase(100)
fmt.Println(a)}//定义Increse方法
func (tz *TZ) Increase(num int) {
//相同类型的才能一起运算,num的int类型要强制转换为TZ
*tz += TZ(num)
}
文章图片
接口interface
接口是一个或多个方法签名的集合
只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示
声明实现了哪个接口,这称为 Structural Typing
接口只有方法声明,没有实现,没有数据字段
接口可以匿名嵌入其它接口,或嵌入到结构中
将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个
复制品的指针,既无法修改复制品的状态,也无法获取指针
只有当接口存储的类型和对象都为nil时,接口才等于nil
接口调用不会做receiver的自动转换
接口同样支持匿名字段方法
接口也可实现类似OOP中的多态
空接口可以作为任何类型数据的容器
//USB 接口
type USB interface {
//Name方法,返回接口的名称
Name() string
//Connect方法,用来连接
Connect()
}// 1、PhoneConnecter 结构实现 USB接口
type PhoneConnecter struct {
name string
}// 2、定义PhoneConnecter结构的Name()方法
func (pc PhoneConnecter) Name() string {
//返回结构的名称
return pc.name
}// 3、定义PhoneConnecter结构的Connect()方法
func (pc PhoneConnecter) Connect() {
//输出信息!!
fmt.Println("Conneting... OK !", pc.name)
}func main() {var a USB
//给name字面值初始化
a = PhoneConnecter{"Phone"}
a.Connect()}
文章图片
嵌入接口实现
package mainimport (
"fmt"
)//USB 接口
type USB interface {
//Name方法,返回接口的名称
Name() string
//嵌入Connecter方法,用来连接
Connecter
}//嵌入Connectertype Connecter interface {
Connect()
}// 1、PhoneConnecter 结构实现 USB接口
type PhoneConnecter struct {
name string
}// 2、定义PhoneConnecter结构的Name()方法
func (pc PhoneConnecter) Name() string {
//返回结构的名称
return pc.name
}// 3、定义PhoneConnecter结构的Connect()方法
func (pc PhoneConnecter) Connect() {
//输出信息!!
fmt.Println("Conneting... OK !", pc.name)
}func main() {// var a USB
// 给name字面值初始化
// a = PhoneConnecter{"Phone"}// 通过接收USB类型的参数的Disconnect函数来判断是否实现了
a := PhoneConnecter{"Phone is ok"}
a.Connect()
Disconnect(a)}func Disconnect(usb USB) {//通过类型判断哪个设备断开了,usb.(判断的类型)
if pc, ok := usb.(PhoneConnecter);
ok {
fmt.Println("Disconnected:", pc.name)
return
}fmt.Println("Unknow decive.")
}
文章图片
空接口,可以实现类拟于其它语言class的继承
package mainimport (
"fmt"
)//USB 接口
type USB interface {
//Name方法,返回接口的名称
Name() string
//嵌入Connecter方法,用来连接
Connecter
}//嵌入Connectertype Connecter interface {
Connect()
}// 1、PhoneConnecter 结构实现 USB接口
type PhoneConnecter struct {
name string
}// 2、定义PhoneConnecter结构的Name()方法
func (pc PhoneConnecter) Name() string {
//返回结构的名称
return pc.name
}// 3、定义PhoneConnecter结构的Connect()方法
func (pc PhoneConnecter) Connect() {
//输出信息!!
fmt.Println("Conneting... OK !", pc.name)
}func main() {// var a USB
// 给name字面值初始化
// a = PhoneConnecter{"Phone"}// 通过接收USB类型的参数的Disconnect函数来判断是否实现了
a := PhoneConnecter{"Phone is ok"}
a.Connect()
Disconnect(a)}//interface{}空接口,任何类型都是实现空接口
func Disconnect(usb interface{}) {//通过类型判断哪个设备断开了,usb.(判断的类型)switch v := usb.(type) {
case PhoneConnecter:
fmt.Println("Disconnected:", v.name)
default:
fmt.Println("Unknow decive.")
}}
文章图片
接口的转换
反射reflection
反射可大大提高程序的灵活性,使得 interface{} 有更大的发挥余地
反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
反射会将匿名字段作为独立字段(匿名字段本质)
想要利用反射修改对象状态,前提是 interface.data 是 settable,
即 pointer-interface
- 通过反射可以“动态”调用方法
获取字段的信息,类型的信息,和字段的值
package mainimport (
"fmt"
"reflect"
)//定义User结构type User struct {
Idint
Name string
Ageint
}//定义User结构的方法
func (u User) Hello() {
fmt.Println("hello world.")
}func main() {
u := User{1, "OK", 12}
//u是以值拷备的形式传到Info当中
Info(u)
}//定义Info函数,参数为空接口转入结构
func Info(o interface{}) {
//TypeOf获得接口的类型
t := reflect.TypeOf(o)
//打印类型的名称
fmt.Println("Type:", t.Name())//取值
v := reflect.ValueOf(o)
fmt.Println("Fields:")for i := 0;
i < t.NumField();
i++ {
//通过索引取得字段
f := t.Field(i)
//取得字段的值
val := v.Field(i).Interface()//按格式,打印
fmt.Printf("%6s:%v = %v\n", f.Name, f.Type, val)}//迭代取得方法的信息
for i := 0;
i < t.NumMethod();
i++ {
m := t.Method(i)
fmt.Printf("%6s:%v\n", m.Name, m.Type)
}}
文章图片
反射匿名和嵌入字段 示例
//定义User结构type User struct {
Idint
Name string
Ageint
}type Manager struct {
User
title string
}func main() {
m := Manager{User: User{1, "OK", 12}, title: "manager"}
//取得类型
t := reflect.TypeOf(m)fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1}))
}
文章图片
通过反射来修改值 示例一
package mainimport (
"fmt"
"reflect"
)func main() {
x := 123
//反射出地址
v := reflect.ValueOf(&x)
//调用Elem方法,SetInt 改变数值
v.Elem().SetInt(999)
fmt.Println(x)
}
文章图片
通过反射来修改值 示例二
package mainimport (
"fmt"
"reflect"
)type User struct {
Idint
Name string
Ageint
}func main() {
u := User{1, "ok", 12}
Set(&u)
fmt.Println(u)
}func Set(o interface{}) {
v := reflect.ValueOf(o)
//如果不是指针的话,打印错误,return
if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
fmt.Println("xxx")
return
} else {
//取得实际对象
v = v.Elem()
}//判断如果找不到Name的话,return
f := v.FieldByName("Name")
if !f.IsValid() {
fmt.Println("BAD")
return
}
//判断如果是Name是reflect.String就修改值
if f.Kind() == reflect.String {
f.SetString("BYEBYE")
}}
文章图片
通过反射来动态修改方法 示例一
通过反射来动态调用Hello方法
package mainimport (
"fmt"
"reflect"
)type User struct {
Idint
Name string
Ageint
}func (u User) Hello(name string) {
//实现User结构Hello方法
fmt.Println("hello", name, ",my name is ", u.Name)
}func main() {
u := User{1, "ok", 12}
//取得发射的User结构
v := reflect.ValueOf(u)
//取得反射的User结构的方法Hello
mv := v.MethodByName("Hello")//args是reflect.Value类型的Slice
args := []reflect.Value{reflect.ValueOf("joe")}
//调用Call方法执行
mv.Call(args)}
文章图片
定义一个结构,通过反射来打印其信息,并调用方法
待续。。。。
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 第三节|第三节 快乐和幸福(12)
- android第三方框架(五)ButterKnife
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 三十年后的广场舞大爷
- 一百二十三夜,请嫁给我
- 2018年9月5日,星期三,天气晴
- 即将到手三百万