【发布时间】:2018-12-10 07:50:46
【问题描述】:
这个问题没有我想的那么清楚,我会问一个更好的问题。但我不想在上面标记重复。所以我已经标记了我自己的问题。如果您可以帮助将其删除,以免混淆社区。请只做那些需要的。当你在它的时候,请不要对我投反对票。抱歉不清楚
我是 golang 的新手,刚刚掌握了窍门。
我通过 Tour of Go 学习,然后根据自己的理解使用它。 我在Interfaces 并开始以我自己的理解来实施。 这里是Go PlayGround Link
第 1 步:我制作了 3 种类型,一个 int、一个结构和一个接口
package main
import (
"fmt"
)
type MyInt int
type Pair struct {
n1, n2 int
}
type twoTimeable interface {
result() (int, int)
}
第 2 步:然后我为指针接收器实现了 twoTimeable,因为它改变了基础值。
func (p *Pair) result() (int, int) {
p.n1 = 2 * p.n1
p.n2 = 2 * p.n2
return p.n1, p.n2
}
func (m *MyInt) result() (int, int) {
*m = 2 * (*m)
return int(*m), 0
}
第 3 步:然后我在 main 函数中声明并分配了 MyInt、Pair 及其对应的指针。我还声明了 twoTimeable 接口
mtemp := MyInt(2)
var m1 MyInt
var m2 *MyInt
var p1 Pair
var p2 *Pair
m1, m2, p1, p2 = MyInt(1), &mtemp, Pair{3, 4}, &Pair{5, 6}
var tt twoTimeable
fmt.Println(" Values : ", m1, *m2, p1, *p2, tt)
第 4 步:我分配了 MyInt,Pair 及其指针,调用实现的方法并打印。
tt = m1
fmt.Println(tt.result())
fmt.Printf("Value of m1 %v\n", m1)
tt = m2
fmt.Println(tt.result())
fmt.Printf("Value of m2 %v\n", *m2)
tt = p1
fmt.Println(tt.result())
fmt.Printf("Value of p1 %v\n", p1)
tt = p2
fmt.Println(tt.result())
fmt.Printf("Value of p2 %v\n", *p2)
显示错误:
prog.go:41:5: cannot use m1 (type MyInt) as type twoTimeable in assignment:
MyInt does not implement twoTimeable (result method has pointer receiver)
prog.go:49:5: cannot use p1 (type Pair) as type twoTimeable in assignment:
Pair does not implement twoTimeable (result method has pointer receiver)
我还阅读了this question,我知道 m1 和 p1 不可寻址,这就是它无法编译的原因。
但是如果我使用 p1 或 m1 p1/m1.result()(自动取消引用 FTW),方法 result() 就可以正常工作
现在在第 2 步中,我将指针接收器更改为值接收器,并将 *m 更改为 m(我知道输出发生了变化)
func (p Pair) result() (int, int) {
p.n1 = 2 * p.n1
p.n2 = 2 * p.n2
return p.n1, p.n2
}
func (m MyInt) result() (int, int) {
m = 2 * (m)
return int(m), 0
}
它突然不显示编译错误。对于 m2 和 p2 不应该这样,因为现在没有使用 *MyInt 和 *Pair 实现结果
这意味着如果接口方法实现有值接收者 tt 可以同时保存指针和值。 但是当接口方法实现有指针接收器时,它不能保存非指针。
Q1:为什么在值接收器接口方法(p MyInt)结果()上使用指针(tt = m2)很好,但在指针接收器接口方法(p *MyInt)上使用值(tt = m1)结果( )。
现在让我们回到指针接收器。
如果函数接受参数(tt twoTimeable)我将能够调用 tt.result(),而不管 tt 是否是指向类型的指针,是否有一种方法,给定的 result() 仅由指针接收器定义。
请看下面的代码:
func doSomething(tt twoTimeable) {
temp1, temp2 := tt.result()
fmt.Print("doing something with ", temp1, temp2)
}
由于 tt 可以是任何预定义类型(指针或非指针),接受参数(tt *twoTimeable,如果我能做到的话)似乎不是一个解决方案,或者我是否依赖函数用户来提供指针.如果我不必更改基础值,即使用值接收器,这不是问题,因为 tt 可以保存值或指向该值的指针
我总是接受答案。
【问题讨论】:
-
请查看play.golang.org/p/fvFvsONstaK 以了解我使用值接收器并且它没有显示编译错误的其他情况
-
您的 Playground 代码显示了对值接收器(此处为 Pair)的常见误解:在底层 Pair 的 copy 上调用方法 Pair.result。此副本在第 19 行和第 20 行被修改。方法完成后,修改后的副本不再存在。这_与接口无关。
-
问题被误解了,我会在以后的问题中更清楚。但是现在 如果接口 twoTimeable 是用 (m *MyInt) 实现的,那么可以为 twoTimeable 类型的变量分配一个 *MyInt 类型的变量。但是如果你改变实现,使得接收者变成 (m MyInt),一个 twoTimeable 类型的变量可以保存 MyInt 和 *MyInt。为什么?
-
如果你真的感兴趣:想出一个小例子,用合理和简短的名字来显示所有 one例子中的行为。这种“如果你改变实现”只会让讨论变得复杂。
-
您可能会将您的问题分成 2 或 3 个不同的问题,1 个问题似乎是为什么 play.golang.org/p/rIQnPjrhLPL(您的代码的简化部分)会导致错误。另一个问题可能是为什么将 result() 方法更改为采用非指针
func (m MyInt) result() (int, int) {不会更改MyInt的值。另一个问题可能是“如何只创建一个结果方法,当分配给twoTimeable接口时,它适用于指针和非指针版本。保持你的问题简短而清晰。
标签: go