2013-10-30 11 views
8

sân chơi liên kết: http://play.golang.org/p/Ebf5AuJlcPSự hiện diện của phương pháp không liên quan trong giao diện ngắt văn bản/mẫu?

type Foo interface {} 

type Bar interface { 
    ThisIsABar() 
} 

// Person implements both Foo and Bar 
type Person struct { 
    Name string 
} 

func (p Person) ThisIsABar() {} 

type FooContext struct { 
    Something Foo 
} 

type BarContext struct { 
    Something Bar 
} 

func main() { 
    t := template.Must(template.New("test").Parse("{{ .Something.Name }}\n")) 

    // This works fine. 
    if err := t.Execute(os.Stdout, FooContext{Person{"Timmy"}}); err != nil { 
     fmt.Printf("Error: %s\n", err) 
    } 

    // With BarContext, containing the exact same Person but wrapped in a 
    // different interface, it errors out. 
    if err := t.Execute(os.Stdout, BarContext{Person{"Timmy"}}); err != nil { 
     fmt.Printf("Error: %s\n", err) 
    } 
} 

Khi tôi làm một bản mẫu (thông qua các gói text/template) chứa {{ .Something.Name }}, tôi có thể đi qua giao diện Foo mà không chứa các phương pháp, và nó hoạt động tốt. Nhưng nếu tôi đi qua giao diện Bar thay vào đó, tôi nhận được:

executing "test" at <.Something.Name>: can't evaluate field Name in type main.Bar 

Tại sao sự hiện diện của một phương pháp không liên quan về giao diện, mà thậm chí không được sử dụng, ảnh hưởng đến việc vẽ của mẫu không?

+1

bản sao có thể có của [mẫu sẽ không đánh giá các trường là loại giao diện dưới dạng kiểu cơ bản] (http://stackoverflow.com/questions/19554209/template-wont-evaluate-fields-that-are-interface-type -as-the-base-type) – nemo

Trả lời

6

Văn bản/mẫu là giao diện vỏ đặc biệt {}, vì vậy hàm được gọi có thể có giao diện kiểu trả về {}, v.v. Thêm phương thức vào giao diện có nghĩa là phát hiện không còn kích hoạt nữa.

http://golang.org/src/pkg/text/template/exec.go#L323

323  for _, cmd := range pipe.Cmds { 
324   value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. 
325   // If the object has type interface{}, dig down one level to the thing inside. 
326   if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { 
327    value = reflect.ValueOf(value.Interface()) // lovely! 
328   } 
329  } 

BarContext.Something là một Bar (một giao diện). A Bar không có tên trường. Nếu bạn muốn sử dụng một giao diện ở đó, bạn sẽ cần phải cung cấp dữ liệu thông qua một phương thức là một phần của giao diện.

+0

Bạn đã xác minh rằng mã này có chịu trách nhiệm về hành vi không? Tôi nghĩ rằng đó là thay vì thực hiện ['gián tiếp'] (http://stackoverflow.com/a/19555267/1643939). Nhưng có lẽ tôi đã bỏ lỡ điều gì đó. – nemo

+0

Ồ, điều đó thật bất ngờ. Tôi bằng cách nào đó đã không tìm thấy http://stackoverflow.com/questions/19554209/template-wont-evaluate-fields-that-are-interface-type-as-the-underlying-type nhưng kết thúc với cùng một giải pháp: chỉ sử dụng 'giao diện {}' khi truyền các thứ cho khuôn mẫu. – Thomas

Các vấn đề liên quan