1. golang方法
go语言没有面向对象的特征,也没有类对象的概念。但是,可以使用结构体来模拟这些特征,我们都知道面向对象里面有类方法等概念。我们可以声明一些方法,属于某个结构体。
在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称之为方法(method)
。本质上,一个方法则是一个和特殊类型关联的函数。
一个面向对象的程序会用方法来表达其属性和对应的操作,这样使用这个对象的用户就不需要直接去操作对象,而是借助方法来做这些事情。
在 Go 语言中,可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法。
方法总是绑定对象实例,并隐式将实例作为第一实参(receiver)
1.1 go语言放的语法
Go中的方法,是一种特殊的函数,定义于struct之上(与struct关联、绑定),被称为struct的接受者(receiver)。
通俗的讲,方法就是有接受者的函数。
- 语法格式:
type mytype struct{}
func (recv mytype)my_method(para) return_type{}
func (recv *mytype)my_method(para) return_type{}
type mytype struct{}
func (recv mytype)my_method(para) return_type{}
func (recv *mytype)my_method(para) return_type{}
mytype
:定义一个结构体
recv
:接受该方法的结构体(receiver)
my_method
:方法名称
para
:参数列表
return_type
:返回值类型
从语法格式可以看出,一个方法和一个函数非常相似,多了一个接受类型
package main
import "fmt"
// 属性
type Person struct {
name string
}
// 方法
// (per Person)接收者 receiver
func (per Person) eat() {
fmt.Printf("eat...: %v\n", per.name)
}
func (per Person) sleep() {
fmt.Printf("sleep...: %v\n", per.name)
}
// other
type Customer struct {
name string
}
func (customer Customer) login(name string, pwd string) bool {
if name == "tom" && pwd == "123" {
return true
} else {
return false
}
}
func main() {
cus := Customer{
"tom",
}
logins := cus.login("tom", "123")
fmt.Printf("logins: %v\n", logins)
/*per := Person{
"tom",
}
per.eat()
per.sleep()*/
}
package main
import "fmt"
// 属性
type Person struct {
name string
}
// 方法
// (per Person)接收者 receiver
func (per Person) eat() {
fmt.Printf("eat...: %v\n", per.name)
}
func (per Person) sleep() {
fmt.Printf("sleep...: %v\n", per.name)
}
// other
type Customer struct {
name string
}
func (customer Customer) login(name string, pwd string) bool {
if name == "tom" && pwd == "123" {
return true
} else {
return false
}
}
func main() {
cus := Customer{
"tom",
}
logins := cus.login("tom", "123")
fmt.Printf("logins: %v\n", logins)
/*per := Person{
"tom",
}
per.eat()
per.sleep()*/
}
- go语言方法的注意事项
1.方法的receiver type并非一定是struct类型,type定义的类型别名、slice、map、channel、func类型等都可以
2.struct结合它的方法就等价于面向对象中的类。只不过struct可以和它的方法拆开,并非一定要属于同一个文件,但必须属于同一个包。
3.方法有两种接受类型:(T Type)和(T *Type)
,它们之间有区别。
4.方法就是函数,所以Go中中没有方法重载(overload)的说法,也就是说同一个类型中的所有方法名必须都唯一。
5.如果receiver是一个指针类型,则会自动解除引用
6.方法和type是分开的,意味着实例的行为(behavior)和数据存储(field)是分开的,但是它们通过receiver建立起关联关系。
1.2 go方法接收者类型
结构体实例,有值类型和指针类型,那么方法的接受者是结构体,那么有值类型和指针类型。区别就是接收者是否复制结构体副本。值类型复制,指针类型不复制。
package main
import "fmt"
func main() {
type Person struct {
name string
}
p1 := Person{
"tom",
}
p2 := &Person{
"tom",
}
fmt.Printf("p1: %T\n", p1)
fmt.Printf("p2: %T\n", p2)
}
#输出结果
p1: main.Person
p2: *main.Person
package main
import "fmt"
func main() {
type Person struct {
name string
}
p1 := Person{
"tom",
}
p2 := &Person{
"tom",
}
fmt.Printf("p1: %T\n", p1)
fmt.Printf("p2: %T\n", p2)
}
#输出结果
p1: main.Person
p2: *main.Person
- 传参结构体例子
package main
import "fmt"
func test1() {
type Person struct {
name string
}
p1 := Person{
"tom",
}
p2 := &Person{
"tom",
}
fmt.Printf("p1: %T\n", p1)
fmt.Printf("p2: %T\n", p2)
}
type Person1 struct {
name string
}
func showPerson(per Person1) {
per.name = "tom"
}
func showPerson2(per *Person1) {
//per.name自动解引用
per.name = "tom"
}
func main() {
p1 := Person1{
"tom...",
}
p2 := &Person1{
"tom...",
}
showPerson(p1)
fmt.Printf("p1: %v\n", p1)
fmt.Println("----------------------")
showPerson2(p2)
fmt.Printf("p2: %v\n", *p2)
//从结果看,p1是值传递,拷贝了副本,本地发生了改变,而p2是指针类型,地址没有变化
}
#结果
p1: {tom...}
----------------------
p2: {tom}
package main
import "fmt"
func test1() {
type Person struct {
name string
}
p1 := Person{
"tom",
}
p2 := &Person{
"tom",
}
fmt.Printf("p1: %T\n", p1)
fmt.Printf("p2: %T\n", p2)
}
type Person1 struct {
name string
}
func showPerson(per Person1) {
per.name = "tom"
}
func showPerson2(per *Person1) {
//per.name自动解引用
per.name = "tom"
}
func main() {
p1 := Person1{
"tom...",
}
p2 := &Person1{
"tom...",
}
showPerson(p1)
fmt.Printf("p1: %v\n", p1)
fmt.Println("----------------------")
showPerson2(p2)
fmt.Printf("p2: %v\n", *p2)
//从结果看,p1是值传递,拷贝了副本,本地发生了改变,而p2是指针类型,地址没有变化
}
#结果
p1: {tom...}
----------------------
p2: {tom}
1.3 方法的值类型和指针类型接受者
值类型和指针类型接受者,本质上和函数传参道理相同
package main
import "fmt"
type Person1 struct {
name string
}
func (per Person1) showPerson3() {
per.name = "tom"
}
func (per *Person1) showPerson4() {
//per.name自动解引用
per.name = "tom"
}
func main() {
p1 := Person1{
"tom...",
}
p2 := &Person1{
"tom...",
}
//从结果看,p1是值传递,拷贝了副本,本地发生了改变,而p2是指针类型,地址没有变化
p1.showPerson3()
fmt.Printf("p1: %v\n", p1)
fmt.Println("----------------------")
p2.showPerson4()
fmt.Printf("p2: %v\n", *p2)
}
package main
import "fmt"
type Person1 struct {
name string
}
func (per Person1) showPerson3() {
per.name = "tom"
}
func (per *Person1) showPerson4() {
//per.name自动解引用
per.name = "tom"
}
func main() {
p1 := Person1{
"tom...",
}
p2 := &Person1{
"tom...",
}
//从结果看,p1是值传递,拷贝了副本,本地发生了改变,而p2是指针类型,地址没有变化
p1.showPerson3()
fmt.Printf("p1: %v\n", p1)
fmt.Println("----------------------")
p2.showPerson4()
fmt.Printf("p2: %v\n", *p2)
}
2. 面向对象和面向过程
package main
import "fmt"
//实现2数相加
//面向过程
func Add01(a, b int) int {
return a + b
}
//面向对象,通过方法,就是给某个类型绑定一个函数
type long int
//a 叫接收者,接收者就是传递一个参数
func (a long) Add02(b long) long {
return a + b
}
func main() {
var s1 int
s1 = Add01(2, 3)
fmt.Println("s1 = ", s1)
//定义一个变量
var s2 long = 2
//调用方法格式: 变量名.函数(所需参数)
r := s2.Add02(3)
fmt.Println("r = ", r)
//面向对象只是换了一种表现形式
}
package main
import "fmt"
//实现2数相加
//面向过程
func Add01(a, b int) int {
return a + b
}
//面向对象,通过方法,就是给某个类型绑定一个函数
type long int
//a 叫接收者,接收者就是传递一个参数
func (a long) Add02(b long) long {
return a + b
}
func main() {
var s1 int
s1 = Add01(2, 3)
fmt.Println("s1 = ", s1)
//定义一个变量
var s2 long = 2
//调用方法格式: 变量名.函数(所需参数)
r := s2.Add02(3)
fmt.Println("r = ", r)
//面向对象只是换了一种表现形式
}