无法在Go中从另一个包中定义接收器。

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

Can't define receiver from another package in Go

问题

我是一个Golang的初学者,对这门语言的一些概念还不太理解。我非常喜欢它,但是网上的例子都非常简单,没有解释正确的开发方式。

我想要使用MySQL配置数据库连接。我创建了一个名为dbconfig的包,其中包含了dbconfig.go文件,还有一个名为datastructure的包,其中包含了接口文件,以及另一个名为entity的包,其中包含了实体文件。

以下是文件结构:

main.go:

import (
	y "github.com/danyalov/shebeke/dbconfig"
	"github.com/danyalov/shebeke/routes"
	_ "github.com/go-sql-driver/mysql"
	"github.com/labstack/gommon/log"
)

func main() {
	db, err := y.InitDB("mysql", "root:root@tcp(localhost:3306)/dbtest?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	e := routes.NewConnection(db)
	e.Logger.Fatal(e.Start(":9898"))
}

routes.go:

import (
	"github.com/danyalov/shebeke/datastructure"
	y "github.com/danyalov/shebeke/dbconfig"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func NewConnection(db *y.DB) *echo.Echo {
	e := echo.New()
	env := Env{db}
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	e.GET("/contracts", env.GetContracts)
	e.GET("/contract/:id", env.GetContractByID)

	return e
}

type Env struct {
	contract datastructure.Contract
}

services.go:

import (
	"github.com/labstack/echo"
	"log"
	"net/http"
	"strconv"
)

func (env *Env) GetContracts(c echo.Context) error {
	contracts, err := env.contract.GetContracts()
	if err != nil {
		log.Fatal(err)
	}
	return c.JSON(http.StatusOK, &contracts)
}

dbconfig.go:

import (
	"database/sql"
	"fmt"
	"github.com/labstack/gommon/log"
)

type DB struct {
	*sql.DB
}

//InitDB initialize mysql database
func InitDB(driver, path string) (*DB, error) {
	db, err := sql.Open(driver, path)
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	} else {
		fmt.Println("Connected to DB")
	}
	return &DB{db}, err
}

datastructure/contract.go:

import y "github.com/danyalov/shebeke/datastructure/entity"

type Contract interface {
	GetContracts() (y.Contracts, error)
	GetContractByID(id int) (y.Contract, error)
}

datastructure/entity/contract.go:

import (
	"github.com/labstack/gommon/log"
	"time"
)

type Contract struct {
	ID         int       `json:"id"`
	State      string    `json:"state"`
	StartDate  time.Time `json:"start_date"`
	FinishDate time.Time `json:"finish_date"`
}

type Contracts []Contract

func (db *DB) GetContracts() (c Contracts, err error) {
	rows, err := db.Query("select * from contract")
	if err != nil {
		log.Fatal(err)
	}

	contract := Contract{}
	for rows.Next() {
		err = rows.Scan(&contract.ID, &contract.State, &contract.StartDate, &contract.FinishDate)
		c = append(c, contract)
	}
	return c, err
}

为什么我无法将dbconfig包中的DB类型作为方法接收器导入到entity包中?我得到了Unresolved type 'DB'的错误。

这是我这个项目的工作副本(Git),我将dbconfig.go放在了entity中,但我不喜欢这样做,我认为这不是dbconfig文件的正确位置。

在Go中,配置数据库的正确文件结构是什么样的?也许你在Git上有自己的示例或教程?

英文:

I'm a beginner in Golang and can't understand some concepts in this language. I like it very much, but every examples on the web are very simple and not explain the correct way of developing.
I want to configure db connection with MySQL. I create a package dbconfig with file dbconfig.go and package dastructure with interfaces files and another package entity with entities files.
This is the structure:
无法在Go中从另一个包中定义接收器。

main.go:

import (
	y "github.com/danyalov/shebeke/dbconfig"
	"github.com/danyalov/shebeke/routes"
	_ "github.com/go-sql-driver/mysql"
	"github.com/labstack/gommon/log"
)

func main() {
	db, err := y.InitDB("mysql", "root:root@tcp(localhost:3306)/dbtest?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	e := routes.NewConnection(db)
	e.Logger.Fatal(e.Start(":9898"))
}

routes.go:

import (
	"github.com/danyalov/shebeke/datastructure"
	y "github.com/danyalov/shebeke/dbconfig"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func NewConnection(db *y.DB) *echo.Echo {
	e := echo.New()
	env := Env{db}
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	e.GET("/contracts", env.GetContracts)
	e.GET("/contract/:id", env.GetContractByID)

	return e
}

type Env struct {
	contract datastructure.Contract
}

services.go:

import (
	"github.com/labstack/echo"
	"log"
	"net/http"
	"strconv"
)

func (env *Env) GetContracts(c echo.Context) error {
	contracts, err := env.contract.GetContracts()
	if err != nil {
		log.Fatal(err)
	}
	return c.JSON(http.StatusOK, &contracts)
}

dbconfig.go:

import (
	"database/sql"
	"fmt"
	"github.com/labstack/gommon/log"
)

type DB struct {
	*sql.DB
}

//InitDB initialize mysql database
func InitDB(driver, path string) (*DB, error) {
	db, err := sql.Open(driver, path)
	if err != nil {
		log.Fatal(err)
	}
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	} else {
		fmt.Println("Connected to DB")
	}
	return &DB{db}, err
}

datastructure/contract.go:

import y "github.com/danyalov/shebeke/datastructure/entity"

type Contract interface {
	GetContracts() (y.Contracts, error)
	GetContractByID(id int) (y.Contract, error)
}

datastructure/entity/contract.go:

import (
	"github.com/labstack/gommon/log"
	"time"
)

type Contract struct {
	ID         int       `json:"id"`
	State      string    `json:"state"`
	StartDate  time.Time `json:"start_date"`
	FinishDate time.Time `json:"finish_date"`
}

type Contracts []Contract

func (db *DB) GetContracts() (c Contracts, err error) {
	rows, err := db.Query("select * from contract")
	if err != nil {
		log.Fatal(err)
	}

	contract := Contract{}
	for rows.Next() {
		err = rows.Scan(&contract.ID, &contract.State, &contract.StartDate, &contract.FinishDate)
		c = append(c, contract)
	}
	return c, err
}

Why can't I import DB type from dbconfig package into entity package as a method receiver? I get Unresolved type 'DB' error.

This is my working copy(Git) of this project, I put dbconfig.go inside the entity, but I don't like it, I think it's incorrect place for dbconfig file.

What is the correct file structure for configuring db in Go? Maybe you have your own examples in Git or some tutorial?

答案1

得分: 28

你只能在同一个包中定义类型的方法。在这种情况下,你的DB类型是在dbconfig包中定义的,所以你的entity包不能在其上定义方法。

在这种情况下,你的选择是将GetContracts定义为一个函数,而不是一个方法,并将*dbconfig.DB作为参数传递给它,或者通过在dbconfig中导入你的entity包并在那里编写GetContracts(作为方法或函数,两种方式都可以)。第二种选项可能是更好的选择,因为从设计的角度来看,让除了数据库包之外的其他包创建 SQL 查询字符串会破坏抽象性。

英文:

You can only define methods on a type defined in that same package. Your DB type, in this case, is defined within your dbconfig package, so your entity package can't define methods on it.

In this case, your options are to make GetContracts a function instead of a method and hand it the *dbconfig.DB as an argument, or to invert the dependency by importing your entity package in dbconfig and write GetContracts there (as a method or function, works either way). This second one may actually be the better option, because, from a design perspective, it breaks abstraction to have packages other than your database package creating SQL query strings.

答案2

得分: 4

这样做的直接方法是在你自己的包中用一个类型包装该类型:

type MyRouterGroup struct {
    *gin.RouterGroup
}

func InitRouter() *gin.Engine {
    r := gin.Default()
    v1Group := &MyRouterGroup{r.Group("v1")}
    v1Group.MyReceiverMethod()
}
英文:

The straightforward way to do this is to wrap the type with a type in your own package:

type MyRouterGroup struct {
	*gin.RouterGroup
}

func InitRouter() *gin.Engine {
    r := gin.Default()
    v1Group := &MyRouterGroup{r.Group("v1")}
    v1Group.MyReceiverMethod()
}

huangapple
  • 本文由 发表于 2016年12月13日 05:15:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/41109708.html
匿名

发表评论

匿名网友

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

确定