簡體   English   中英

如何從Go / Golang中的另一個方法表達式中訪問方法表達式(結構函數)?

[英]How do I access a method expression (struct function) from within another method expression in Go / Golang?

我正在嘗試清理我的Go / Golang項目中的代碼。 我認為以一種面向對象的方式創建模型可能是慣用的,例如:

  • db.Users.GetID("john") (在“用戶”表中做某事)
  • db.Purchases.GetTotal() (在“ db.Purchases.GetTotal() ”表中做某事)

但是,這樣做的一個問題是,數據庫函數無法根據需要自行調用。

這是我所談論的一個小巧的示例:

package main

import "fmt"

// A model that contains all of the structs for our database tables
type Model struct {
    Users
    Purchases
}

// A struct for functions that have to do with the "users" table
type Users struct {}
func (self *Users) Exists(id int) bool {
    // Check to see if the user exists
    // SELECT id FROM users WHERE id = ?
    return true // (omitted)
}

// A struct for functions that have to do with the "purchases" table
type Purchases struct {}
func (self *Purchases) Count(id int) int {
    // First validate that the user exists
    if db.Users.Exists(id) == false { // This fails <--------------
        return 0
    } else {
        // Get the count of that user's purchases
        // SELECT COUNT(user_id) FROM purchases WHERE user_id = ?
        return 50 // (omitted)
    }
}

func main() {
    db := Model{}
    numPurchases := db.Purchases.Count(123)
    if numPurchases != 0 {
        fmt.Println("User #123 has", numPurchases, "purchases!")
    } else {
        fmt.Println("User #123 does not exist!")
    }
}

這會導致錯誤:

undefined: db in db.Users

如果我將其更改為Users.Exists而不是db.Users.Exists

./test.go:22: invalid method expression Users.Exists (needs pointer receiver: (*Users).Exists)
./test.go:22: Users.Exists undefined (type Users has no method Exists)

注意,在這個人為的例子中,驗證用戶的存在是沒有意義的。 但是,要點是,如果確實有一些重要的內容需要驗證,則數據庫函數應該具有調用某些其他數據庫函數的能力。

我如何才能解決這個問題?

(編輯-為清晰起見,修改了代碼段。)

您想做的事在Go中是不可能的。 Users.Exists是一個方法表達式 有了這些,您可以采用一種方法並將其轉換為簡單的函數類型。

userExists := Users.Exists

user := User{}

// now userExists can be called as a regular function with
// first argument of a Users type
exists := userExists(&user, id)

結果,您無法像上面提到的那樣完全構建模型。

Go並不是一種完全面向對象的語言,因此您不應嘗試在其中嚴格復制OOP結構和習慣用語。 在上述情況下,如果需要Exists函數,則可以始終將Users移到單獨的程序包中,並將Exists定義為函數:

package user

type Users struct {}

// other methods on Users type

func Exists(id int) bool {
    // check to see if user exists
}

您現在可以撥打以下電話:

import "user"

user.Exists(id)

初始化結構后,可以使用自我引用填充它。 由於我是Go語言的新手,所以我不確定它是否是慣用語言,但似乎還可以。

固定代碼段:包主

import "fmt"

// A model that contains all of the structs for our database tables
type Model struct {
    Users
    Purchases
}

// A struct for functions that have to do with the "users" table
type Users struct {
    db *Model
}
func (self *Users) Exists(id int) bool {
    // Check to see if the user exists
    // SELECT id FROM users WHERE id = ?
    return true // (omitted)
}

// A struct for functions that have to do with the "purchases" table
type Purchases struct {
    db *Model
}
func (self *Purchases) Count(id int) int {
    // First validate that the user exists
    if self.db.Users.Exists(id) == false { // This succeeds now <--------------
        return 0
    } else {
        // Get the count of that user's purchases
        // SELECT COUNT(user_id) FROM purchases WHERE user_id = ?
        return 50 // (omitted)
    }
}

func main() {
    // Initialize the model and fill it with helpful self-references
    db := Model{}
    db.Users.db = &db
    db.Purchases.db = &db
    // In practice, you will want to do this in some sort of custom constructor, like:
    // var db Model*
    // db := Model.NewModel(db)

    numPurchases := db.Purchases.Count(123)
    if numPurchases != 0 {
        fmt.Println("User #123 has", numPurchases, "purchases!")
    } else {
        fmt.Println("User #123 does not exist!")
    }
}

如果需要在Users struct字段,則可以使用db.Exists(2)甚至Users.Exists(db, 2)都有效。 像這樣的工作示例代碼:

package main

import "fmt"

type Users struct {
    Ids []int
}

func (t Users) Exists(id int) bool {
    for _, v := range t.Ids {
        if v == id {
            return true
        }
    }
    return false
}

func main() {
    db := Users{[]int{1, 2}}
    r1 := db.Exists(2)
    r2 := Users.Exists(db, 2)
    fmt.Println(r1, r2) // true true
}

您可以像db.Exists(2)甚至是Users.Exists(db, 2)一樣使用它
兩者都是有效的。 您可以將Users struct僅用於分組方法,例如以下工作示例代碼:

package main

import "fmt"

type Users struct{}

var Ids = []int{1, 2}

func (t Users) Exists(id int) bool {
    for _, v := range Ids {
        if v == id {
            return true
        }
    }
    return false
}

func main() {
    db := Users{}
    r1 := db.Exists(2)
    r2 := Users.Exists(db, 2)
    fmt.Println(r1, r2) // true true
}

您不需要分組時可以使用UserExists(2) ,例如以下工作示例代碼:

package main

import "fmt"

type Users struct{}

var Ids = []int{1, 2}

func UserExists(id int) bool {
    for _, v := range Ids {
        if v == id {
            return true
        }
    }
    return false
}

func main() {
    r1 := UserExists(2)
    fmt.Println(r1) // true
}

因此,在您的情況下,這可以正常工作:

package main

import "fmt"

type Model struct {
    Users
    Purchases
}

type Users struct{}

var users Users

func (*Users) Exists(id int) bool {
    return true
}

type Purchases struct{}

func (*Purchases) Count(id int) int {
    if users.Exists(id) == false {
        return 0
    } else {
        return 50
    }
}

func main() {
    db := Model{}
    numPurchases := db.Purchases.Count(123)
    if numPurchases != 0 {
        fmt.Println("User #123 has", numPurchases, "purchases!")
    }
}

輸出:

User #123 has 50 purchases!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM