添加一个永远不会调用的func会改善行为

时间:2012-06-14 19:00:47

标签: go

以下代码会产生不合需要的

  

[20010101 20010102]。

当取消注释String func时,它会产生更好的效果(但不是我的实现):

  

[{20010101 1.5} {20010102 2.5}]

但是从不调用String func。 我看到DateValue中的Date是匿名的,因此DateValue正在使用func (Date) String

所以我的问题是:

1)这是一个语言问题,fmt.Println实施问题,还是    别的什么?注意:如果我从:

切换
func (*DateValue) String() string

func (DateValue) String() string

我的功能至少被召唤,随之而来的是恐慌。因此,如果我真的想要我的方法,我可以这样做,但假设DateValue实际上是一个非常大的对象,我只想通过引用传递。

2)将匿名字段与...混合的好策略是什么?    像Stringer和json编码这样使用反射的功能    在封面下?例如,添加String或MarshalJSON方法    对于恰好用作匿名字段的类型可能会导致    奇怪的行为(就像你只打印或编码整体的一部分)。

package main

import (
    "fmt"
    "time"
)

type Date int64

func (d Date) String() string {
    t := time.Unix(int64(d),0).UTC()
    return fmt.Sprintf("%04d%02d%02d", t.Year(), int(t.Month()), t.Day())
}

type DateValue struct {
    Date 
    Value float64
}

type OrderedValues []DateValue

/*
// ADD THIS BACK and note that this is never called but both pieces of
// DateValue are printed, whereas, without this only the date is printed
func (dv *DateValue) String() string {
    panic("Oops")
    return fmt.Sprintf("DV(%s,%f)", dv.Date, dv.Value )
}
*/

func main() {
    d1, d2 := Date(978307200),Date(978307200+24*60*60)
    ov1 := OrderedValues{{ d1, 1.5 }, { d2, 2.5 }}
    fmt.Println(ov1)
}

2 个答案:

答案 0 :(得分:1)

这是因为你传递了一片DateValues而不是DateValue指针。由于您已为*DataValue定义了String方法,因此*DateValue符合Stringer接口。这也可以防止DateValue通过其匿名Date成员实现Stringer接口,因为只能使用值类型(DateValue)或指针类型(*DateValue)中的一个来实现接口。因此,当fmt.Println正在打印切片的内容时,它会看到元素不是Stringers,并使用默认的struct格式而不是您定义的方法,给出[{20010101 1.5} {20010102 2.5}]

您可以将OrderedValues设为[]*DateValue或定义func (dv DateValue) String() string而不是指针版本。

答案 1 :(得分:0)

根据@SteveM的说法,我将其提炼为更简单的测试用例:

package main

import "fmt"

type Fooable interface {
  Foo()
}

type A int

func (a A) Foo() { }

type B struct {
  A
}

// Uncomment the following method and it will print false
//func (b *B) Foo() { }

func main() {
  var x interface{} = B{}
  _, ok := x.(Fooable)
  fmt.Println(ok) // prints true
}

换句话说,Foo方法在定义B的{​​{1}}方法时不属于Foo方法集。

从阅读规范,我没有看到正在发生的事情的明确解释。最近的部分似乎位于selectors上的部分:

  

对于类型为T或* T的值x,其中T不是接口类型,x.f   表示在T处的最浅深度处的场或方法   是这样的。

我可以看到这个解释正在发生的事情的唯一方法是,当它在*B中寻找最浅深度的方法Foo时,它会考虑{{1}的方法也是出于某种原因(即使我们正在考虑类型B而不是*B);并且B中的*B确实比Foo中的*B浅,所以它需要一个作为候选者;然后它发现Foo不起作用,因为它在A而不是Foo,所以它完全摆脱*B(即使有效一个继承自B)。

如果确实发生了这种情况,那么我同意OP,因为这非常违反向<{1}}添加方法会产生相反的结果< em>从Foo删除方法。

也许更熟悉Go的人可以澄清这一点。