实现interface的receiver是value type和pointer type的区别?

#### 如题,直接上代码,希望能从本质上解决我的问题。 ``` // 定义一个Reader的接口 type Reader interface { Read() } // 定义一个实现接口的类 type NReader struct{} // receiver是value类型 func (nr NReader) Read() { // code } // 定义另一个实现接口的类 type FReader struct{} // receiver是pointer类型 func (fr *FReader) Read() { // code } // 定义Reader变量 var r Reader // 定义NReader变量 var nra NReader var nrb *NReader // 定义FReader变量 var fra FReader var frb *FReader // 将NReader和FReader变量分别赋给接口r r = nra // 语句一,可以赋值 r = nrb // 语句二,可以赋值 r = fra // 语句三,报错FReader没有实现接口Reader r = frb // 语句四,可以赋值 ``` 所以我这里的疑问是为什么语句三会报错?如果语句三是错的,那语句二为什么又是正确的?到底interface变量r里面是如何保存实现接口的相关类的?interface中有个指向type类型的指针,这个指针里面保存的是什么样的类型,值类型还是指针类型?求本质上的答案~
已邀请:

h12 - https://h12.io/about

赞同来自: 三只熊 haoc7 root666

解释清楚这个问题需要引用Go Spec里的三个概念:

1. [Assignability](https://golang.org/ref/spec#Assignability "Assignability")
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
* T is an interface type and x implements T.

2. [Interface types](https://golang.org/ref/spec#Interface_types "Interface types")
A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface.

3. [Method sets](https://golang.org/ref/spec#Method_sets "Method sets")
The method set of any other type T consists of all methods declared with receiver type T. The method set of the corresponding pointer type `*T` is the set of all methods declared with receiver `*T` or T (that is, it also contains the method set of T).

三只熊 - GO狂热追随者

#### Go源码实在难啃的一笔
在FAQ中找到了这个问题:
> Why do T and *T have different method sets?
From the Go Spec:

> The method set of any other named type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).
If an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, there is no useful way for a method call to obtain a pointer.

> Even in cases where the compiler could take the address of a value to pass to the method, if the method modifies the value the changes will be lost in the caller. As an example, if the Write method of bytes.Buffer used a value receiver rather than a pointer, this code:

>var buf bytes.Buffer
io.Copy(buf, os.Stdin)
would copy standard input into a copy of buf, not into buf itself. This is almost never the desired behavior.

附上几个关于`interface under hood`的文章(文章写的很棒)
* [go interface by Lance Taylor](https://www.airs.com/blog/archives/277)
* [go interface by Russ Cox](https://research.swtch.com/interfaces)

要回复问题请先登录注册