2016-07-03 114 views
7

我在Golang的世界裏有2天的歷史,並且通過去參觀。我忍不住注意到一個特殊的地方,我似乎無法用恰當的推理來達到目的。爲什麼我不能將類型的值賦給接口類型指針實現方法的接口?

該代碼是完全運行:

package main 
import (
    "fmt" 
    "math" 
) 
type Vertex struct{ 
    X,Y float64 
} 
type Abser interface{ 
    Abs() float64 
} 
func (v Vertex) Abs() float64{ //method with value receiver argument 
    return math.Sqrt(v.X*v.X+v.Y*v.Y) 
} 
func main(){ 
    var myVer Vertex = Vertex{3,4} 
    var inter Abser 
    inter = &myVer //assigning *Vertex type to inter 
    fmt.Println(inter.Abs()) 
} 

同時,下面的代碼顯示一個錯誤:

package main 
import (
    "fmt" 
    "math" 
) 
type Vertex struct{ 
    X,Y float64 
} 
type Abser interface{ 
    Abs() float64 
} 
func (v *Vertex) Abs() float64{ //method with pointer receiver argument 
    return math.Sqrt(v.X*v.X+v.Y*v.Y) 
} 
func main(){ 
    var myVer Vertex = Vertex{3,4} 
    var inter Abser 
    inter = myVer //assigning Vertex type to inter 
    fmt.Println(inter.Abs()) 
} 

錯誤是:

interface.go:18: cannot use myVer (type Vertex) as type Abser in assignment: Vertex does not implement Abser (Abs method has pointer receiver)

直到達到的這一部分我可以理解Go的創作者已經放棄了諸如

(*v).method1name()

(&v).method2name()

因此,具有值接收器的方法可以與值和指針一起使用,反之亦然。

爲什麼語言在使用接口時會區分兩者(值和指針)?如果在這裏可以應用相同的參考/解引用原則,不是更方便嗎?

我希望我不會錯過太明顯的東西。 謝謝!

+0

我來這裏討論相同的例子。我無法把頭圍住它。它在這裏:https://tour.golang.org/methods/9 –

回答

4

Intro++ to Go Interfaces」 說明了問題:

*Vertex is a type. It’s the 「pointer to a Vertex 」 type. It’s a distinct type from (non-pointer) Vertex . The part about it being a pointer is part of its type.

你需要類型的一致性。

Methods, Interfaces and Embedded Types in Go」:

The rules for determining interface compliance are based on the receiver for those methods and how the interface call is being made.
Here are the rules in the spec for how the compiler determines if the value or pointer for our type implements the interface :

  • 對應的指針類型*T的方法集與接收機*TT

This rule is stating that if the interface variable we are using to call a particular interface method contains a pointer, then methods with receivers based on both values and pointers will satisfy the interface.

  • 的方法的一組的所有方法任何其他類型的集合T由接收器類型爲T的所有方法組成。

This rule is stating that if the interface variable we are using to call a particular interface method contains a value, then only methods with receivers based on values will satisfy the interface.

Karrot Kakeanswermethod set也詳述go wiki

The method set of an interface type is its interface.

The concrete value stored in an interface is not addressable, in the same way that a map element is not addressable.
Therefore, when you call a method on an interface, it must either have an identical receiver type or it must be directly discernible from the concrete type.

Pointer- and value-receiver methods can be called with pointers and values respectively, as you would expect.
Value-receiver methods can be called with pointer values because they can be dereferenced first.
Pointer-receiver methods cannot be called with values, however, because the value stored inside an interface has no address.

( 「沒有地址」 實際上意味着它是not addressable

+1

[Intro ++ to Go Interfaces](http://npf.io/2014/05/intro-to-go-interfaces/)很清楚地解決了我的疑問。它明確指出: 「..接口中的值在隱藏的內存位置,因此編譯器無法自動獲取指向該內存的指針(用Go語言來說,這被稱爲「不可尋址」)。「 我想推薦對任何人都面臨同樣的疑慮,我正面臨着,訪問鏈接,並通過它一次,這將是值得你的時間。 @VonC,謝謝你的美妙的鏈接:-) –

+1

@TanmayGarg真的,我詳細的不可尋址的部分在我最後編輯的答案中,最後。 – VonC

+0

啊,是的。再次感謝:-) –

3

method set爲指針類型包含值接收方法,但設置爲值爲的方法不包括指針接收方法。爲值類型設置的方法不包括指針接收方法,因爲存儲在接口中的值不是addressable

2

不錯的問題。
這是Golang類型系統:Vertex*Vertex不同類型
看到這個澄清樣品:
可以使用type Vertex2 Vertex來定義新Vertex2型,這些是不同類型的太:

,而這是工作:

package main 

import "fmt" 
import "math" 

func main() { 
    var myVer Vertex = Vertex{3, 4} 
    var inter Abser = myVer //assigning Vertex type to inter 
    fmt.Println(inter.Abs()) 
} 

func (v Vertex) Abs() float64 { //method with pointer receiver argument 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

type Vertex struct { 
    X, Y float64 
} 
type Abser interface { 
    Abs() float64 
} 

這是行不通的:

package main 

import "fmt" 
import "math" 

func main() { 
    var myVer Vertex = Vertex{3, 4} 
    var inter Abser = myVer //assigning Vertex type to inter 
    fmt.Println(inter.Abs()) 
} 

type Vertex2 Vertex 

func (v Vertex2) Abs() float64 { //method with pointer receiver argument 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

type Vertex struct { 
    X, Y float64 
} 
type Abser interface { 
    Abs() float64 
} 

錯誤是:

\ m.go:8:
頂點不實現Abser(缺少阿布斯方法)

:在分配不能使用myVer(式頂點)類型Abser

完全一樣的錯誤與樣品:

package main 

import "fmt" 
import "math" 

func main() { 
    var myVer Vertex = Vertex{3, 4} 
    var inter Abser = myVer //assigning Vertex type to inter 
    fmt.Println(inter.Abs()) 
} 

func (v *Vertex) Abs() float64 { //method with pointer receiver argument 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

type Vertex struct { 
    X, Y float64 
} 
type Abser interface { 
    Abs() float64 
} 

因爲兩個頂點和Vertex2是不同的類型。
這個工程太

package main 

import "fmt" 
import "math" 

func main() { 
    var inter Abser = &Vertex{3, 4} //assigning &Vertex type to inter 
    fmt.Printf("inter: %#[1]v\n", inter) 
    fmt.Println(inter.Abs()) 
} 

func (v Vertex) Abs() float64 { //method with pointer receiver argument 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

type Vertex struct { 
    X, Y float64 
} 
type Abser interface { 
    Abs() float64 
} 

輸出:

inter: &main.Vertex{X:3, Y:4} 
5 

因爲:
A型可具有與之相關聯的方法集。接口類型的方法集是它的接口。 任何其他類型T的方法集合由所有用接收方類型T聲明的方法組成。相應的指針類型* T的方法集合是用接收方* T或T聲明的所有方法的集合(也包含方法集T)。其他規則適用於包含匿名字段的結構,如結構類型部分所述。任何其他類型都有一個空方法集。在方法集中,每個方法必須具有唯一的非空白方法名稱。

類型的方法集確定類型實現的接口以及可以使用該類型的接收方調用的方法。
ref:https://golang.org/ref/spec#Method_sets

0

存儲在接口中的值不可尋址 - 但爲什麼?請參閱here獲取答案。這是因爲當接口中存儲不同類型B的值時,指向接口中類型A的值的指向A的指針將會失效。

相關問題