嵌入式方法能够访问“父级”字段吗?

huangapple go评论69阅读模式
英文:

Can embedded methods access "parent" fields?

问题

背景

我已经阅读了相当多的规范和代码测试,我认为答案是否定的,但我想确保我没有漏掉任何东西。

目标

基本上,我想为Go创建一个类似于Active Record风格的ORM,因为我喜欢它的可读性以及它与后端数据存储的抽象程度。我宁愿写user.Save()而不是data.Save(user),通过在用户结构体上嵌入常见的CRUD方法。

示例

package main

import (
	"fmt"
	"reflect"
)

func main() {
	test := Foo{Bar: &Bar{}, Name: "name"}
	test.Test()
}

type Foo struct {
	*Bar
	Name string
}

func (s *Foo) Method() {
	fmt.Println("Foo.Method()")
}

type Bar struct {
}

func (s *Bar) Test() {
	t := reflect.TypeOf(s)
	v := reflect.ValueOf(s)
	fmt.Printf("model: %+v %+v %+v\n", s, t, v)
	fmt.Println(s.Name)
	s.Method()
}

问题

是否有办法从嵌入的方法中访问顶级字段(不确定Go中这些字段的正确术语是什么)(例如:s.Names.Method())?

感谢您抽出时间帮助新的Gopher。

英文:

Background

I've done a fair amount of spec reading and code testing and I think the answer is no, but I want to make sure I'm not missing anything.

Goal

Basically, I'm trying to create a Active Record style ORM for Go, because I like how readable it is and how abstracted it is from its back end data store. I'd rather write user.Save() than data.Save(user) by embedding common CRUD methods on the user struct.

Example

package main

import (
	"fmt"
	"reflect"
)

func main() {
	test := Foo{Bar: &Bar{}, Name: "name"}
	test.Test()
}

type Foo struct {
	*Bar
	Name string
}

func (s *Foo) Method() {
	fmt.Println("Foo.Method()")
}

type Bar struct {
}

func (s *Bar) Test() {
	t := reflect.TypeOf(s)
	v := reflect.ValueOf(s)
	fmt.Printf("model: %+v %+v %+v\n", s, t, v)
	fmt.Println(s.Name)
	s.Method()
}

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

Question

Is there a way to make top-level fields (not sure what the correct term in Go is for these) accessible from embedded methods (eg: s.Name or s.Method()?

Thank you donating your time to a new Gopher.

答案1

得分: 3

Go语言不提供对你所需的支持:Test方法的接收者是一个Bar指针,无法判断它是否被嵌入。

如果你真的想这样做,一种选择是在Bar中添加一个interface{}成员,并要求将其设置为包含类型。初始化该成员可以由创建该值的人负责,或者要求调用者将该值传递给某个ORM方法进行设置。这并不是特别优雅,但可能是你能做的最好的办法。

除此之外,将API结构化为db.Save(user)而不是user.Save()真的那么糟糕吗?前者提供了一种明显的扩展到多个数据库的方式,而后者似乎更有可能依赖全局状态。

英文:

Go doesn't provide any support for what you're after: the receiver of your Test method is a Bar pointer, and there is no way to tell whether it is embedded or not.

If you really want to go this route, one option would be to add an interface{} member to Bar and require that types that it be set to the containing type. Initialising this member could either be the responsibility of whoever created the value, or perhaps require callers to pass the value to some ORM method to set it. This isn't particularly pretty, but it's probably the best you can do.

With that out of the way, is it really that bad to structure the API as db.Save(user) rather than user.Save()? The former offers an obvious way to extend to multiple databases, while the latter seems more likely to rely on global state.

答案2

得分: 0

(如果我正确理解了你的问题),不,嵌入不是继承。听起来你实际上想要的是一个接口。

type Saver interface {
    Save() error
}

然后相关的对象可以实现这个接口。

你可以有一个公共的结构体 base 或其他名称,它实现了公共方法,然后每个更高级的结构体可以嵌入 base,以便它们可以共享实现。

英文:

(If I understood your question correctly,) no, embedding isn't inheritance. It sounds like what you're actually after is an interface

type Saver interface {
    Save() error
}

then the relevant parties can implement that.

You can have a common struct base or whatever that implements common methods and then each higher-level struct can embed base to allow them to share implementation.

huangapple
  • 本文由 发表于 2013年11月24日 05:12:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/20167935.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定