The Go FAQ answers a question关于在方法ä¸é€‰æ‹©by-value与by-pointer接收器的定义。该ç”案ä¸çš„一个陈述是:
 Â如果该类型的æŸäº›æ–¹æ³•å¿…须具有指针接收器,则其余方法也应如æ¤ï¼Œå› æ¤æ— 论使用何ç§ç±»åž‹ï¼Œæ–¹æ³•é›†éƒ½æ˜¯ä¸€è‡´çš„。
è¿™æ„味ç€å¦‚果我的数æ®ç±»åž‹æœ‰ä¸€äº›å˜å¼‚æ•°æ®çš„æ–¹æ³•ï¼Œå› æ¤éœ€è¦æŒ‰æŒ‡é’ˆæŽ¥æ”¶å™¨ï¼Œæˆ‘应该使用by-pointer接收器æ¥ä¸ºè¯¥æ•°æ®ç±»åž‹å®šä¹‰çš„所有方法。
å¦ä¸€æ–¹é¢ï¼Œ"fmt"
包调用String()
ç•Œé¢æŒ‰å€¼å®šä¹‰çš„Stringer
方法。如果使用接收器by-pointer定义String()
方法,则当关è”æ•°æ®ç±»åž‹ä½œä¸ºfmt.Println
(或其他fmt
æ ¼å¼åŒ–方法)的å‚数给出时,ä¸ä¼šè°ƒç”¨å®ƒã€‚这使得除了使用接收器按值实现String()
æ–¹æ³•ä¹‹å¤–åˆ«æ— é€‰æ‹©ã€‚
如åŒå¸¸è§é—®é¢˜è§£ç”å»ºè®®çš„é‚£æ ·ï¼Œå¦‚ä½•æ»¡è¶³fmt
接å£çš„Stringer
è¦æ±‚,那么如何与按值与按指针的选择ä¿æŒä¸€è‡´ï¼Ÿ
编辑:
为了强调我æ到的问题的本质,考虑一ç§æƒ…况,其ä¸ä¸€ä¸ªæ•°æ®ç±»åž‹å…·æœ‰ä¸€ç»„用接收器按值定义的方法(包括String())。然åŽï¼Œäººä»¬å¸Œæœ›æ·»åŠ 一个改å˜è¯¥æ•°æ®ç±»åž‹çš„é™„åŠ æ–¹æ³• - 所以他用接收器指针定义它,并且(为了ä¿æŒä¸€è‡´ï¼Œæ ¹æ®FAQç”案),他还更新了è¦ä½¿ç”¨çš„æ•°æ®ç±»åž‹çš„所有其他方法。 - 指针接收器。æ¤æ›´æ”¹å¯¹ä½¿ç”¨æ¤æ•°æ®ç±»åž‹çš„方法的任何代ç æ²¡æœ‰ä»»ä½•å½±å“ - 但是对于fmt
æ ¼å¼åŒ–函数的调用(现在需è¦å°†æŒ‡é’ˆä¼ 递给å˜é‡è€Œä¸æ˜¯å…¶å€¼ï¼Œå¦‚更改之å‰ï¼‰ã€‚å› æ¤ï¼Œä¸€è‡´æ€§è¦æ±‚仅在fmt
的上下文ä¸å˜åœ¨é—®é¢˜ã€‚æ ¹æ®æŽ¥æ”¶å™¨ç±»åž‹è°ƒæ•´ä¸€ä¸ªå˜é‡ä¸ºfmt.Println
(或类似函数)的方å¼çš„需è¦æ‰“ç ´äº†è½»æ¾é‡æž„一个包的能力。
ç”案 0 :(得分:3)
å¦‚æžœä½¿ç”¨æŒ‡é’ˆæŽ¥æ”¶å™¨å®šä¹‰æ–¹æ³•ï¼Œåˆ™åº”ä½¿ç”¨å¹¶ä¼ é€’æŒ‡é’ˆå€¼è€Œä¸æ˜¯éžæŒ‡é’ˆå€¼ã€‚è¿™æ ·åšçš„ä¼ é€’å€¼ç¡®å®žå®žçŽ°äº†Stringer
,而fmt
包没有问题“检测â€å¹¶è°ƒç”¨æ‚¨çš„String()
方法。
示例:
type Person struct {
Name string
}
func (p *Person) String() string {
return fmt.Sprintf("Person[%s]", p.Name)
}
func main() {
p := &Person{Name: "Bob"}
fmt.Println(p)
}
输出(在Go Playground上å°è¯•ï¼‰ï¼š
Person[Bob]
如果è¦å°†Person
ç±»åž‹çš„å€¼ä¼ é€’ç»™fmt.Println()
而ä¸æ˜¯ç±»åž‹ä¸º*Person
的指针,是的,确实ä¸ä¼šè°ƒç”¨Person.String()
。但是如果Person
çš„æ‰€æœ‰æ–¹æ³•éƒ½æœ‰æŒ‡é’ˆæŽ¥æ”¶å™¨ï¼Œé‚£å°±æ˜¯å¼ºæŒ‡ç¤ºï¼Œä½ åº”è¯¥ä½¿ç”¨ç±»åž‹åŠå…¶å€¼ä½œä¸ºæŒ‡é’ˆï¼ˆé™¤éžä½ ä¸æ‰“算使用它的方法)。
是的,您必须知é“是å¦å¿…须使用Person
或*Person
。处ç†å®ƒã€‚å¦‚æžœä½ æƒ³ç¼–å†™æ£ç¡®æœ‰æ•ˆçš„程åºï¼Œä½ 必须知é“çš„ä¸ä»…仅是使用指针还是éžæŒ‡é’ˆå€¼ï¼Œæˆ‘ä¸çŸ¥é“ä¸ºä»€ä¹ˆè¿™å¯¹ä½ æ¥è¯´å¾ˆé‡è¦ã€‚如果您ä¸çŸ¥é“,请查找它,如果您是懒惰的,请使用指针作为方法集(类型)指针值包å«æŒ‡é’ˆå’ŒéžæŒ‡é’ˆæŽ¥æ”¶å™¨çš„方法。
Person
的作者也å¯ä»¥ä¸ºæ‚¨æä¾›NewPerson()
工厂函数,您å¯ä»¥ä¾èµ–它æ¥è¿”回æ£ç¡®ç±»åž‹çš„值(例如Person
如果方法有值接收器,并且*Person
å¦‚æžœæ–¹æ³•æœ‰æŒ‡é’ˆæŽ¥æ”¶å™¨ï¼Œé‚£ä¹ˆä½ å°±ä¸å¿…知é“使用哪个。
回ç”ç¨åŽå°†ä¸€ä¸ªå¸¦æŒ‡é’ˆæŽ¥æ”¶å™¨çš„æ–¹æ³•æ·»åŠ åˆ°ä»¥å‰åªæœ‰å¸¦æœ‰å€¼æŽ¥æ”¶å™¨çš„方法的类型:
是的,æ£å¦‚您在问题ä¸æ‰€æè¿°çš„é‚£æ ·ï¼Œå¯èƒ½ä¸ä¼šç ´å现有代ç ,但继ç»ä½¿ç”¨éžæŒ‡é’ˆå€¼å¯èƒ½æ— 法从åŽæ¥æ·»åŠ 的带指针接收器的方法ä¸èŽ·ç›Šã€‚
我们å¯èƒ½ä¼šé—®ï¼šè¿™æ˜¯ä¸€ä¸ªé—®é¢˜å—ï¼Ÿä½¿ç”¨ç±»åž‹æ—¶ï¼Œæ‚¨åˆšåˆšæ·»åŠ çš„æ–°æ–¹æ³•ä¸å˜åœ¨ã€‚所以原始代ç 没有å‡è®¾å®ƒçš„å˜åœ¨ã€‚所以它应该ä¸æ˜¯é—®é¢˜ã€‚
第二个考虑:类型åªæœ‰å…·æœ‰å€¼æŽ¥æ”¶å™¨çš„æ–¹æ³•ï¼Œå› æ¤å¯ä»¥å¾ˆå®¹æ˜“地å‡è®¾é€šè¿‡å®ƒä»¬çš„使用,值是ä¸å¯å˜ï¼Œå› 为具有值接收器的方法ä¸èƒ½æ”¹å˜è¯¥å€¼ã€‚使用该类型的代ç å¯èƒ½å·²å»ºç«‹åœ¨æ¤åŸºç¡€ä¸Šï¼Œå‡è®¾å®ƒæ²¡æœ‰è¢«å…¶æ–¹æ³•æ›´æ”¹ï¼Œå› æ¤ä»Žå¤šä¸ªgoroutineä¸ä½¿ç”¨å®ƒå¯èƒ½æ£ç¡®åœ°çœç•¥äº†æŸäº›åŒæ¥ã€‚
æ‰€ä»¥æˆ‘è®¤ä¸ºå°†æŒ‡é’ˆæŽ¥æ”¶å™¨çš„æ–°æ–¹æ³•æ·»åŠ åˆ°ä»¥å‰åªæœ‰å…·æœ‰å€¼æŽ¥æ”¶å™¨çš„方法的类型ä¸åº”该是“ä¸é€æ˜Žçš„â€ï¼Œæ·»åŠ æ¤æ–°æ–¹æ³•çš„人有责任修改æ¤ç±»åž‹çš„使用“切æ¢â€åˆ°æŒ‡é’ˆå¹¶ç¡®ä¿ä»£ç ä¿æŒå®‰å…¨å’Œæ£ç¡®ï¼Œæˆ–者处ç†éžæŒ‡é’ˆå€¼ä¸å…·å¤‡è¿™ç§æ–°æ–¹æ³•çš„事实。
<强>æ示:强>
如果æŸä¸ªç±»åž‹å°†æ¥å¯èƒ½æœ‰mutatoræ–¹æ³•ï¼Œæ‚¨åº”è¯¥å¼€å§‹ä½¿ç”¨å¸¦æœ‰æŒ‡é’ˆæŽ¥æ”¶å™¨çš„æ–¹æ³•åˆ›å»ºå®ƒã€‚è¿™æ ·åšå¯ä»¥é¿å…以åŽå¿…须完æˆä¸Šè¿°è¿‡ç¨‹ã€‚
å¦ä¸€ä¸ªæ示å¯èƒ½æ˜¯å®Œå…¨éšè—类型,åªå‘布接å£ã€‚è¿™æ ·åšï¼Œè¿™ç§ç±»åž‹çš„用户ä¸å¿…知é“接å£æ˜¯å¦åŒ…è£…æŒ‡é’ˆï¼Œè¿™æ— å…³ç´§è¦ã€‚它们接收接å£å€¼ï¼Œå¹¶è°ƒç”¨æŽ¥å£çš„方法。包作者负责处ç†æ£ç¡®çš„方法接收器,并返回实现接å£çš„适当类型。客户看ä¸åˆ°è¿™ä¸€ç‚¹ï¼Œä»–们ä¸ä¾èµ–于æ¤ã€‚他们所看到和使用的åªæ˜¯ç•Œé¢ã€‚
ç”案 1 :(得分:2)
 Â为了强调我æ到的问题的本质,考虑一ç§æƒ…况,其ä¸ä¸€ä¸ªæ•°æ®ç±»åž‹å…·æœ‰ä¸€ç»„用接收器按值定义的方法(包括String())。然åŽï¼Œäººä»¬å¸Œæœ›æ·»åŠ 一个改å˜è¯¥æ•°æ®ç±»åž‹çš„é™„åŠ æ–¹æ³• - 所以他用接收器指针定义它,并且(为了ä¿æŒä¸€è‡´ï¼Œæ ¹æ®FAQç”案),他还更新了è¦ä½¿ç”¨çš„æ•°æ®ç±»åž‹çš„所有其他方法。 - 指针接收器。æ¤æ›´æ”¹å¯¹ä½¿ç”¨æ¤æ•°æ®ç±»åž‹çš„方法的任何代ç æ²¡æœ‰å½±å“ - 但是对于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
}
è¦ä»Žrootä¸ç†è§£è¿™ä¸€ç‚¹ï¼Œæ‚¨åº”该知é“指针方法和值方法与基础ä¸åŒã€‚但是,为方便起è§ï¼Œå°±åƒçœç•¥;
ä¸€æ ·ï¼Œgolang编译器使用没有指针的指针方法查找案例并将其更改回æ¥ã€‚
如æ¤å¤„所述:https://tour.golang.org/methods/6
å›žåˆ°åŽŸå§‹é—®é¢˜ï¼šæŒ‡é’ˆæ–¹æ³•çš„ä¸€è‡´æ€§ã€‚å¦‚æžœä½ ä»”ç»†é˜…è¯»faqï¼Œä½ ä¼šå‘现它是考虑使用值或指针方法的最åŽä¸€éƒ¨åˆ†ã€‚您å¯ä»¥åœ¨container/heap
ä¸æ‰¾åˆ°æ ‡å‡†lib示例ä¸çš„å例:
// 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)
}
事实上,æ£å¦‚FAQ所说,è¦ç¡®å®šæ˜¯å¦ä½¿ç”¨æŒ‡é’ˆæ–¹æ³•ï¼Œè¯·æŒ‰é¡ºåºè€ƒè™‘ä»¥ä¸‹å› ç´ ï¼š