【问题标题】:Golang calling methods on interface pointerGolang在接口指针上调用方法
【发布时间】:2014-01-22 12:17:24
【问题描述】:

我使用Gorp 进行数据库访问,Gorp 有一个标准的DbMap 类型,以及一个Transaction 类型,当您希望能够回滚时。这两种类型都实现了SqlExecutor 接口。

因此,我正在针对SqlExecutor 接口进行编程,因此我可以根据需要使用事务,而无需更改我的代码。

然后我初始化一个 Gorp DbMapTransaction 并将其作为字段属性传入。问题是我需要一个指向 Gorp“对象”的指针,否则如果我使用 Transaction 如果 Gorp“对象”是按值而不是引用传递的,我将如何回滚。

然后我会收到一条消息,例如

r.Gorp.Get undefined (type *gorp.SqlExecutor has no field or method Get)

当我尝试使用我的代码时。如何调用方法?

代码示例如下。

package repositories

import (
    "github.com/coopernurse/gorp"
)


type Repository struct {
    Gorp *gorp.SqlExecutor // <<<< Need pointer so I can rollback
}

func (r *Repository) GetById(i interface{}, key interface{}) interface{} {
    obj, err := r.Gorp.Get(i, key)
    if err != nil {
        panic(err)
    }
    return obj
}

【问题讨论】:

    标签: go


    【解决方案1】:

    也许您对问题的思考过度,或者您可能仍然受到另一种语言的“引用调用”影响:

    1. gorp.SqlExecutor 是一个接口,你永远不会使用指向接口值的指针。永远不能。 (从技术上讲,这是不正确的,但如果您确实需要指向接口的指针,那么您已经掌握了足够的 Go 来理解为什么“永远不会”是一个非常好的建议。)
    2. 永远不要考虑“通过引用调用”。 Go 中没有这样的东西。将指针传递给函数不是“通过引用调用”。把它抛在脑后。

    我假设您没有尝试使用事务并对非指向接口的代码进行回滚?

    背景:在 Go 中,由于两个原因,您传递指向某事物的指针:

    1) 你想这样做,因为你的结构 真的 而且你想避免复制,或者

    2) 你需要,因为被调用者想要修改原始的(这对于带有指针接收器的方法来说很典型)。

    现在接口值非常小(只有两个字),所以原因 1,将指针传递给接口值,不适用。原因 2 在大多数情况下不适用,因为传递指向接口值的指针将允许您更改 interface value 本身,但大多数情况下您希望修改该值存储内部接口值。存储在接口值中的这个值通常是一个指针值,它允许通过调用接口值上的方法来更改结构的值,该接口值包装了指向该结构的指针。这听起来很复杂,但实际上并不复杂:新手 Go 程序员只是不使用指向接口的指针(因为这不会有任何好处),而有经验的 Go 程序员不使用指向接口的指针(因为它不会做太多好)除非他需要修改接口值,通常是在反射期间。

    【讨论】:

    • 我现在传入一个指向接口的非指针,我得到这个消息:cannot use gorp (type gorp.DbMap) as type gorp.SqlExecutor in assignment: gorp.DbMap does not implement gorp.SqlExecutor (Delete method has pointer receiver)
    • 我的删除看起来像这样func (r *Repository) Delete(list ...interface{}) int64 { count, err := r.Gorp.Delete(list...) if err != nil { panic(err) } return count }
    • 这个答案没有用,因为它既没有解释为什么不使用指针也没有建议替代方案。
    • “将指针传递给函数不是“通过引用调用”。把它抛在脑后。”与“由于两个原因而传递指向某事物的指针相矛盾:1)您想要这样做,因为您的结构非常大并且您想避免复制”(如果不传递引用,您怎么能做到这一点确实超出了我的范围!)
    • @Adonis 指针不是“引用”(PL 技术术语)。技术术语“reference”具有口语英语单词“reference”未涵盖的技术含义。我在这里说的不是英语,而是 PL 技术术语。如果传递指针,则传递值,而不是引用(技术术语)。当然指针是引用(英语,口语意思)。但这是 Stack Overflow,而不是英文 101。
    【解决方案2】:
    1. gorp.SqlExecutor 是一个接口,你永远不会使用指针 为接口值。永远不会。

    2. 如果这是您的目标,那么您的目标是错误的。一个 接口是一个包装器,是一个保证行为的契约。如果 您的界面要求方法改变实现 类型,那么实现类型应该是一个指针。指向的指针 接口本身不会突然做出实现类型 可变的。

    3. 你的结构应该是

      type Repository struct {
          Gorp gorp.SqlExecutor 
      }
      
      
      func (r *Repository) GetById(i interface{}, key interface{}) interface{} {
          obj, err := r.Gorp.(gorp.SqlExecutor).Get(i, key)
          if err != nil {
              panic(err)
          }
          return obj
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-08
      • 1970-01-01
      • 2014-07-30
      • 2018-02-28
      • 2015-01-26
      • 2018-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多