关于接口实现的一个小问题

type geometry interface {
area() float64
perim() float64
}

type rect struct {
width, height float64
}
type circle struct {
radius float64
}

func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}

func (c *circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c *circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}

r := rect{3, 4}
c := circle{5}
measure(r)
measure(&c) //如果这样写 measure(c)就不行,也就是说c没有实现相应的接口,报错。必须 传地址进去,意思是&c 实现了接口。
看下面代码:
var cc circle= circle{6}
var ccptr *circle= &cc
fmt.Println(cc.area())
fmt.Println(ccptr.area())
fmt.Println(cc)

既然编译器可以聪明的在适当的时候进行取地址 和 指针解引用 ,为何在接口这里就不行了呢?为什么要区分这么严格呢?


谢谢。

已邀请:

stevewang

赞同来自: gameogre astaxie yong27

方便、灵活和可控之间,需要一个平衡。
调用函数的时候,接收者是T或者*T取决于函数的定义,所以不会有歧义;但是转换成接口的时候,接收者是T或者*T决定了对象是否实现指定接口,所以需要特别区分避免歧义。
而且,如果接收者是*T的方法集实现了某个接口,那么实现接口的对象必须是可取址的,而把T对象传递给函数会导致创建一个不可取址的临时对象,自然这个临时对象就不能转换成接口。

changjixiong - 时常做白日梦的程序员

赞同来自: 三只熊

package main

import (
"fmt"
"math"
)

type geometry interface {
area() float64
perim() float64
}

type rect struct {
width, height float64
}
type circle struct {
radius float64
}

type circle2 circle

func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}

func (c *circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c *circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}

func main() {
r := rect{3, 4}
pr := &rect{3, 4}
//pr = r
//cannot use r (type rect) as type *rect in assignment
//r = pr
//cannot use pr (type *rect) as type rect in assignment

var gr geometry = r
var gpr geometry = pr

gr.area()
gpr.area()

//c := circle{5}
//var gc geometry = c
//cannot use c (type circle) as type geometry in assignment:
//circle does not implement geometry (area method has pointer receiver)
//gc.area()

pc := &circle{5}
var gpc geometry = pc
gpc.area()

}

golang 认为circle没有实现接口,而*circle实现了。
貌似只能智能解引用,把类似c中需要p->f()这样的写法, 通过接引用后用p.f()完成。
没有智能取地址。
interface{}是类似与 void * 类型的指针,可以接收任何值。
然而没有现实接口的类型,不能传。

mars

赞同来自:

并不是同一个类型,这也是golang的语言特性诶

zhr

赞同来自:

我觉得不是一回事吧
在调用方法的时候不区分值和引用是图方便
但是如果在赋值的时候都不分,那你完全都没法控制我需要值还是需要引用了

codinghxl

赞同来自:

go里面我理解interface 应该是一个通用指针类型

要回复问题请先登录注册