Go语言之面向对象-方法

Posted 程序彤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言之面向对象-方法相关的知识,希望对你有一定的参考价值。

golang的方法

作用在指定数据类型上,和指定的数据类型绑定,因此自定义类型都可以有方法,而不仅仅是struct

声明和调用

在这里插入图片描述

type A struct{
Num int
}

func (a A) test{
fmt.Println(a.Num)
}表示A结构体的方法为test()

package main

import(
	"fmt"
	"encoding/json"
)

func main(){
	monster1 := Monster{"李威彤",21}
	fmt.Println(monster1)

	jsonString,_:=json.Marshal(monster1)

	// 实际场景,字段首字母为小写。如何解决,字段使用标签``,即反射机制
	fmt.Println("服务端将会收到json格式的字符串=>",string(jsonString))

	monster1.Name = "小怪兽"
	monster1.shout()
	fmt.Println(monster1) // 由于结构体是值传递,故无用兽不可能在main()中打印出现

}

type Monster struct{
	Name string `json:"name"` // 返回的json格式的字符串中的首字母小写name
	age int `json:"age"`
}

func (m Monster) shout(){ // 结构体Monster的大叫方法
	fmt.Println(m.Name,"叫了一声shout()...")
	m.Name = "无用兽"
	fmt.Println("方法shout()中的:",m)
}

再次表明,结构体为值传递。

结构体指针(原生)

package main

import(
	"fmt"
	"encoding/json"
)

func main(){
	monster1 := Monster{"李威彤1",21}
	fmt.Println(monster1)

	jsonString,_:=json.Marshal(monster1)

	// 实际场景,字段首字母为小写。如何解决,字段使用标签``,即反射机制
	fmt.Println("服务端将会收到json格式的字符串=>",string(jsonString))

	monster1.Name = "小怪兽"
	monster1.shout()
	fmt.Println(monster1) // 由于结构体是值传递,故无用兽不可能在main()中打印出现

	monster2 := Monster{"李威彤2",21}
	(&monster2).cry()
	fmt.Println("main()中的cry()",monster2)
}

type Monster struct{
	Name string `json:"name"` // 返回的json格式的字符串中的首字母小写name
	age int `json:"age"`
}

func (m Monster) shout(){ // 结构体Monster的大叫方法
	fmt.Println(m.Name,"叫了一声shout()...")
	m.Name = "无用兽"
	fmt.Println("方法shout()中的:",m)
}

func (m *Monster) cry(){
	fmt.Println(m.Name,"哭了cry()!")
	(*m).Name="引用-哭哭兽"
	fmt.Println("方法cry()中的 m.Name",m.Name)
	fmt.Println("方法cry()中的 (*m).Name",(*m).Name)
}

go简化结构体指针之后(简便写法)

即main()中的:
(&m).cry() 等价于 m.cry()

结构体指针的cry()方法中:
(*m).Name 等价于 m.Name

package main

import(
	"fmt"
	"encoding/json"
)

func main(){
	monster1 := Monster{"李威彤1",21}
	fmt.Println(monster1)

	jsonString,_:=json.Marshal(monster1)

	// 实际场景,字段首字母为小写。如何解决,字段使用标签``,即反射机制
	fmt.Println("服务端将会收到json格式的字符串=>",string(jsonString))

	monster1.Name = "小怪兽"
	monster1.shout()
	fmt.Println(monster1) // 由于结构体是值传递,故无用兽不可能在main()中打印出现

	monster2 := Monster{"李威彤2",21}
	(&monster2).cry()
	monster2.cry()
	fmt.Println("main()中的cry()",monster2)
}

type Monster struct{
	Name string `json:"name"` // 返回的json格式的字符串中的首字母小写name
	age int `json:"age"`
}

func (m Monster) shout(){ // 结构体Monster的大叫方法
	fmt.Println(m.Name,"叫了一声shout()...")
	m.Name = "无用兽"
	fmt.Println("方法shout()中的:",m)
}

func (m *Monster) cry(){
	fmt.Println(m.Name,"哭了cry()!")
	(*m).Name="引用-哭哭兽"
	m.Name = "引用--哭哭兽"
	fmt.Println("方法cry()中的 m.Name",m.Name)
	fmt.Println("方法cry()中的 (*m).Name",(*m).Name)
}

go方法和函数的区别

对于普通函数,接受者为值类型,不能将指针类型的数据直接传递,反之亦然
对于方法,接受者为值类型,可以直接用指针类型的变量调用方法,反之不然!!

总结:

  1. 不管调用形式如何,那只是一种表现形式。真正决定是值拷贝还是地址拷贝,看这个方法和哪个类型绑定。
  2. 如果是和值类型,比如p Person,结构体是值拷贝。如果是*p Person,则是结构体指针地址拷贝。
package main
import(
	"fmt"
)

type Person struct{
	Name string
}

func test01(p Person){
	fmt.Println(p.Name)
}
func test02(p *Person){
	fmt.Println(p.Name)
}

func (p Person) test03(){
	p.Name = "郑"
	fmt.Println("test03()=",p.Name)
}

func (p *Person) test04(){
	p.Name = "郑my"
	fmt.Println("test04()*=",p.Name)
}

func main(){
	p:= Person{"李"}
	// 对于函数,接受值类型时,不能将地址类型数据直接传递。反之亦然
	test01(p) // testt01(&p)将报错
	test02(&p) // testt02(p)将报错
	
	p.test03() // 标准
	fmt.Println("main()=",p.Name) 
	(&p).test03() // 不标准。test03()本身就是值拷贝传递,你即便使用&p也毫无作用,go做了优化
	fmt.Println("main()=",p.Name)

	(&p).test04() // 标准
	fmt.Println("main()=",p.Name)

	p.test04() // go优化处理,不标准但优雅
	fmt.Println("main()=",p.Name)

	
}

在这里插入图片描述

以上是关于Go语言之面向对象-方法的主要内容,如果未能解决你的问题,请参考以下文章

go语言面向对象之接口

go面向对象之多态即接口(interface)

Go语言之面向对象-多态与类型断言

通学go语言系列之面向对象

go语音之进阶篇方法面向过程和对象函数的区别

区块链技术语言(二十三)——Go语言面向对象:方法