Ela*_*arR 5 methods interface go
Go FAQ 回答了一个关于方法中按值与按指针接收器定义选择的问题。该答案中的陈述之一是:
如果该类型的某些方法必须有指针接收器,其余的也应该如此,因此无论如何使用该类型,方法集都是一致的。
这意味着,如果我对一个数据类型有一些改变数据的方法,因此需要按指针接收器,我应该对为该数据类型定义的所有方法使用按指针接收器。
另一方面,"fmt"包通过 value调用接口中String()定义的方法。如果用接收器按指针定义方法,则当关联的数据类型作为参数提供给(或其他格式化方法)时,将不会调用该方法。这让人们别无选择,只能使用接收器按值实现该方法。StringerString()fmt.PrintlnfmtString()
正如常见问题解答所建议的那样,在满足接口fmt要求的同时,如何与按值与按指针的选择保持一致Stringer?
编辑:
为了强调我提到的问题的本质,考虑一个数据类型,其中包含一组用接收者按值定义的方法(包括 String())。然后一个人希望添加一个额外的方法来改变该数据类型 - 所以他用接收者按指针定义它,并且(为了保持一致,每个常见问题解答)他还更新了该数据类型的所有其他方法以供使用- 指针接收器。此更改对使用此数据类型方法的任何代码的影响为零 - 但用于调用fmt格式化函数(现在需要将指针传递给变量而不是其值,就像更改之前一样)。因此,一致性要求仅在fmt. 需要调整提供变量的方式fmt.Println (或类似功能)基于接收器类型打破了轻松重构一个包的能力。
为了强调我提到的问题的本质,考虑一种情况,其中一个数据类型具有一组用接收者按值定义的方法(包括 String())。然后,有人希望添加一种改变该数据类型的附加方法 - 因此他用接收者指针定义它,并且(为了保持一致,根据常见问题解答答案)他还更新了该数据类型的所有其他方法以供使用-指针接收器。此更改对使用此数据类型的方法的任何代码影响为零 - 但对于 fmt 格式化函数的调用(现在需要像更改之前一样传递指向变量的指针而不是其值)。
这不是真的。所有interface这些和一些类型断言也会受到影响 - 这就是 fmt 受到影响的原因。例如:
package main
import (
"fmt"
)
type I interface {
String() string
}
func (t t) String() string { return "" }
func (p *p) String() string { return "" }
type t struct{}
type p struct{}
func S(i I) {}
func main() {
fmt.Println("Hello, playground")
T := t{}
P := p{}
_ = P
S(T)
//S(P) //fail
}
Run Code Online (Sandbox Code Playgroud)
要从根本上理解这一点,您应该知道指针方法和值方法从本质上来说是不同的。然而,为了方便起见,就像省略 一样;,golang 编译器会查找使用没有指针的指针方法的情况并将其改回来。
正如这里所解释的: https: //tour.golang.org/methods/6
那么回到最初的问题:指针方法的一致性。如果您更仔细地阅读常见问题解答,您会发现这是考虑使用值或指针方法的最后一部分。您可以在标准库示例中找到反例container/heap:
// A PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
return pq[i].priority > pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.index = -1 // for safety
*pq = old[0 : n-1]
return item
}
// update modifies the priority and value of an Item in the queue.
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}
Run Code Online (Sandbox Code Playgroud)
因此,确实,正如常见问题解答所说,要确定是否使用指针方法,请按顺序考虑以下因素: