2016-07-03 108 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的指针将会失效。

相关问题