英文:
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:
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()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论