Loading

方法

十五、方法

1 方法定义

go语言中同时有函数和方法。一个方法就是一个包含了接收器的函数,接收器一般是结构体类型中的字段,也可以是非结构体。它的定义如下:

func (variable_name variable_data_type) function_name() [return_type]{
   /* 函数体*/
}

通俗来说就是定义一个函数,指定一个接收器来接收这个函数。

通过一个示例学习方法的使用:

type Book struct {
	title string
	price int
}

func (book Book) printprice() {
	fmt.Println(book.price)
	book.price += 2
}
func main() {
	book := Book{
		title: "红楼梦",
		price: 58,
	}
	book.printprice()
	fmt.Println(book.price)
}

在上面的示例中,我们定义一个结构体含两个字段;然后定义一个函数,指定接收器为book,此时相当于在Book类型上绑定了一个方法。我们在main函数中可以通过.操作符调用这个方法。

2 值接收器和指针接收器

在上面的示例中我们发现,printprice方法想让price自增2,但实际上原结构体并不会被改变,这是因为我们使用了值接收器。

我们如果想要在方法内更改字段并使得它对调用者可见,需要使用指针接收器。比如下面的例子:

type Book struct {
	title string
	price int
}

func (book *Book) printprice() {
	fmt.Println(book.price)
	// 这里传递的是指针,但是我们仍然可以取到字段。这是go内部自动转化的结果,如果在c或c++中,你需要先对指针解引用
	fmt.Println((*book).price)
	book.price += 2
}
func main() {
	book := Book{
		title: "红楼梦",
		price: 58,
	}
	book.printprice()
	fmt.Println(book.price)
}

使用指针接收器后,在 printprice 方法中对 Book 结构体的字段 price 所做的改变对调用者是可见的,换句话说在方法内修改值,原来的值也会随之改变。

另外补充一点,如果你有c编程的经验,你可能注意到,在操作结构体的字段时,如果在c或c++中,需要先对指针解引用;而在go中不同,指针直接使用.操作符就可以取到字段。

另外,go可以直接使用指针操作,而c/c++不可以,对比c++代码来理解:

struct Book {
    string title;
    int price;
};
void printprice(Book* book){
    (*book).price +=2; // c 解引用
    cout <<book->price<<endl;// c++ 解引用
}
int main() {
    Book book = {"红楼梦",58};
    printprice(&book);
    return 0;
}

那么该如何选择值接收器与指针接收器?如果你想要方法所做的改变对调用者可见,那么就使用指针接收器;否则就使用值接收器。另外,值接收器需要对原结构体拷贝,如果结构体字段很大,那么付出的内存消耗也大。

3 字段方法提升

和结构体的字段提升一样,接收器是匿名字段的结构体,可以直接在外部使用它的方法。

type Book struct {
	title string
	price int
	Author
}

type Author struct {
	name string
	age  int
}

func (a Author) getage() {
	// 接收器为Author
	fmt.Println(a.age)
}

func main() {
	book := Book{
		title: "红楼梦",
		price: 58,
		Author: Author{
			name: "曹雪芹",
			age:  20,
		},
	}
	book.getage() // 可以直接访问Author的绑定方法
	fmt.Println(book.price)
}
posted @ 2021-12-10 16:30  yyyz  阅读(43)  评论(0编辑  收藏  举报