5

golang の使用html/template( と同じ動作text/template)。インターフェイス型のメンバーを持つ構造体がある場合、基になる型のメンバーにアクセスできません (具体的には、インターフェイスを実装しているが、構造体型ではなくインターフェイス型InnerInterfaceを介して返される構造体にあるフィールドにアクセスしようとしています)。 InnerInterface.

http://play.golang.org/p/ZH8wSK83oM

package main

import "fmt"
import "os"
import "html/template"

type InnerInterface interface{ InnerSomeMethod() }

type MyInnerStruct struct { Title string }
func (mis MyInnerStruct)InnerSomeMethod() { fmt.Println("Just to show we're satisfying the interface") }

type MyOuterStruct struct { Inner InnerInterface }


func main() {

    fmt.Println("Starting")


    arg := MyOuterStruct{Inner:MyInnerStruct{Title:"test1"}}

    err := template.Must(template.New("testtmpl").Parse("{{.Inner.Title}}")).Execute(os.Stdout, arg)
    if err != nil { panic(err) }

}

変更:type MyOuterStruct struct { Inner InnerInterface }完全に一般的なインターフェイスに変更します。つまりtype MyOuterStruct struct { Inner interface{} }、適切にレンダリングします。interface{}これは、レンダリング エンジンによって特別に処理されていると思われます。

interface{}このようなフィールドを動的に評価できるようにしたいときはいつでも使用するよりも、これを行うためのより良い方法はありますか?

4

1 に答える 1

5

interface{}それはレンダリング エンジンによって異なる方法で処理されると言って間違いありません。値のみinterface{}がアンパックされ、メソッド セットを持つインターフェイス値はアンパックされません。この背後にある理由は、インターフェイス タイプがある場合、そのタイプを具体的にメソッド セットに制限するためだと思います。したがって、テンプレート エンジンがそのインターフェイスの背後にあるメンバーにアクセスしようとするのは望ましくありません。

indirect「問題」は の関数によってexec.go引き起こされます:

func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
    for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
        if v.IsNil() {
            return v, true
        }
        if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
            break
        }
    }
    return v, false
}

このメソッドは、反映された値の最も深い値を取得するために呼び出されます。ポインター上のポインターにポインターがあると仮定すると、この関数はこれらの最後のものを返します。インターフェイス値についても同様です。肝心なのは、インターフェイス値に 0 を超えるメソッドがあるとすぐに、間接化がそこで止まるということです。まさにあなたが説明している動作。

これは意図された動作のように思われるためTitle() string 、インターフェイスでメソッドを定義し、文字列を返すようにすることができます。

于 2013-10-24T01:24:46.640 に答える