Go語言的receiver又分為value receiver與pointer receiver兩種,兩者區別如下。
Value receiver的型態前不加*
,method的receiver為複製值;
Pointer receiver的型態前加*
,method的receiver為指標。
下面AddTitle()
方法為value receiver。在main()
中被呼叫並修改了Employee.Name
,但並沒有改變原本的employee.Name
的值,因為AddTitle()
的receiver (e Employee)
為呼叫變數的複製值。
package main
import "fmt"
// define struct type 'Employee'
type Employee struct {
Id int
Name string
Age int
}
// method of value receiver
func (e Employee) AddTitle(title string) {
e.Name = title + e.Name // e is the copy value of variable 'employee'
}
func main() {
employee := Employee{1, "John", 33}
employee.AddTitle("Mr. ")
fmt.Println(employee.Name) // John
}
若把AddTitle()
的receiver型態前加上*
則變成pointer receiver,執行結果則變成有修改到變數employee.Name
的值。
package main
import "fmt"
type Employee struct {
Id int
Name string
Age int
}
// method of pointer receiver
func (e *Employee) AddTitle(title string) {
e.Name = title + e.Name // e is the pointer to variable 'employee'
}
func main() {
employee := Employee{1, "John", 33}
employee.AddTitle("Mr. ")
fmt.Println(employee.Name) // Mr. John
}
此外實作interface的方法時,value type的值無法分派到pointer receiver實作的interface變數; 反之pointer type的值可以分派到value receiver實作的interface變數。
這是因為pointer type的method sets同時包含了pointer receiver及value receiver的methods;而value type的method sets只有value receiver的methods。節錄Go規格文件的Method sets:
The method set of any other type
T
consists of all methods declared with receiver typeT
. The method set of the corresponding pointer type*T
is the set of all methods declared with receiver*T
orT
(that is, it also contains the method set ofT
).任意型態
T
的method sets包含了receiverT
的全部methods。Pointer type*T
的method sets包含了receiver*T
及T
的全部methods
例如下面pointer receiver *Employee
實作Worker
interface的Work()
,因此當把Employee
value分派到Worker
變數worker
時會出現編譯錯誤(compile error)訊息如下。
cannot use (Employee literal) (value of type Employee) as Worker value in variable declaration: missing method Work (Work has pointer receiver)
main.go
package main
import "fmt"
type Worker interface {
Work()
}
type Employee struct {
Id int
Name string
Age int
}
// method of pointer receiver
func (e *Employee) Work() {
fmt.Println(e.Name + " works")
}
func main() {
var worker Worker = Employee{1, "John", 33} // compile error
worker.Work()
}
因為Worker
的實作為pointer receiver而非value receiver,因此只能接受pointer type的Employee
值,因為才有包含pointer receiver的method。所以在Employee
literal前加上&
取得pointer即可正確分派到worker
變數。
package main
import "fmt"
type Worker interface {
Work()
}
type Employee struct {
Id int
Name string
Age int
}
// method of pointer receiver
func (e *Employee) Work() {
fmt.Println(e.Name + " works")
}
func main() {
var worker Worker = &Employee{1, "John", 33} // assign pointer of Employee literal to worker
worker.Work()
}
相反地,value receiver實作的interface變數則可同時接收value type或pointer type的值,因為pointer type的method sets同時包含了pointer receiver及value receiver的methods。注意分派pointer type值的worker
變數呼叫的Work()
方法仍是value receiver的method。
package main
import "fmt"
type Worker interface {
Work()
}
type Employee struct {
Id int
Name string
Age int
}
// method of value receiver
func (e Employee) Work() {
fmt.Println(e.Name + " works")
}
func main() {
var worker1 Worker = &Employee{1, "John", 33} // assign pointer of Employee literal to worker1
worker1.Work()
var worker2 Worker = Employee{2, "Mary", 28} // assign value of Employee literal to worker2
worker2.Work()
}
沒有留言:
張貼留言