1

以下のコードは望ましくないものを生成します

[20010101 20010102]。

String 関数のコメントを外すと、より良い結果が得られます (ただし、私の実装ではありません)。

[{20010101 1.5} {20010102 2.5}]

ただし、その String 関数は呼び出されません。DateValue の Date は匿名であるため、func (Date) StringDateValue で使用されていることがわかります。

だから私の質問は:

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)
}
4

2 に答える 2

1

これは、DateValue ポインターではなく、DateValues のスライスを渡したためです。の String メソッドを定義したので*DataValue*DateValueが Stringer インターフェースを満たします。これにより、DateValue が匿名の Date メンバーを介して Stringer インターフェイスを満たすこともできなくなります。インターフェイスを満たすために使用できるのは、値型 ( DateValue) またはポインター型 ( ) のいずれか 1 つだけだからです。*DateValueそのため、fmt.Println がスライスの内容を出力しているとき、要素がストリンガーではないことを認識し、定義したメソッドの代わりにデフォルトの構造体フォーマットを使用して、[{20010101 1.5} {20010102 2.5}].

OrderedValues を にするか、ポインター バージョンの代わりに[]*DateValue定義することができます。func (dv DateValue) String() string

于 2012-06-14T19:22:14.407 に答える
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はメソッドセットの一部ではありません。BFoo*B

仕様を読んでも、何が起こっているのか明確な説明がわかりません。最も近い部分は、セレクターのセクションにあるようです:

タイプ T または *T の値 x の場合、T はインターフェイス タイプではありません。xf は、そのような f が存在する T の最も浅い深さのフィールドまたはメソッドを示します。

Foo何が起こっているのかを説明するこれを見ることができる唯一の方法は、で最も浅い深さでメソッドを探しているときに、何らかの理由でBメソッドも考慮に入れている場合です ( type notを考慮しているにもかかわらず)。inは確かにinよりも浅いので、それを候補として採用します。そして、それが機能しないことがわかります。なぜなら、それは in であり、notであるため、完全に取り除かれます (から継承された有効なものがあっても)。*BB*BFoo*BFooAFoo*BBFooA

これが実際に起こっていることである場合、これは非常に直感に反するという点でOPに同意します にメソッドを追加するとからメソッドが削除*Bされるという逆の結果になります。B

おそらく、Go に詳しい人がこれを明確にすることができます。

于 2012-06-18T02:34:12.317 に答える