以下代码会产生不合需要的
[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)
}
答案 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的人可以澄清这一点。