将变量限制为自身和其他特定包。

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

Restrict variable to itself and to other certain package

问题

我有这样的结构:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── common.go
│   │   └── users.go
│   ├── model
│   │   └── model.go
│   └── queries
│       └── queries.go
├── config
│   └── config.go
└── main.go

所有的查询(SQL查询)都在 queries.go 中:

queries.go:

package queries

const (
    QueryFindUser = `SELECT * FROM users WHERE id=$1` // <------ 这里
)

users.go:

package handler

import (
    "GO_APP/app/model"
    "GO_APP/app/queries"
    "fmt"
    "net/http"
    "strconv"
    "github.com/julienschmidt/httprouter"
    _ "github.com/jinzhu/gorm/dialects/postgres"
    "github.com/jmoiron/sqlx"
)

var db *sqlx.DB

// getUserOr404 gets a User instance if exists, or respond the 404 error otherwise
func getUserOr404(db *sqlx.DB, id int, w http.ResponseWriter, r *http.Request) (*model.User, error) {
    user := model.User{}
    err := db.Get(&user, queries.QueryFindUser, id) // <----- 这里
    return &user, err
}

如果我使用 QueryFindUser(首字母大写),那么它将对所有其他包可见。但我不希望它可以被 config/config.go 等访问。

我希望它仅限于 handler 的模块,不包括 model/model.go

如果我声明 queryFindUser,那么它将仅限于 queries 包,我将无法在其他地方使用它。

如何解决这个问题?而不使它对每个其他包都可见。
我对golang/java还很陌生,这个问题在java中也是一样的。
那么在这种情况下该怎么办?
如果您能提供一些资源,对我来说也会很有帮助。

英文:

I have this structure:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── common.go
│   │   └── users.go
│   ├── model
│   │   └── model.go
│   └── queries
│       └── queries.go
├── config
│   └── config.go
└── main.go

All my queries (SQL ones) are in queries.go:

queries.go:

package queries

const (
	QueryFindUser = `SELECT * FROM users WHERE id=$1` // <------ HERE
)

users.go:

package handler

import (
	"GO_APP/app/model"
	"GO_APP/app/queries"
	"fmt"
	"net/http"
	"strconv"
	"github.com/julienschmidt/httprouter"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"github.com/jmoiron/sqlx"
)

var db *sqlx.DB

// getUserOr404 gets a User instance if exists, or respond the 404 error otherwise
func getUserOr404(db *sqlx.DB, id int, w http.ResponseWriter, r *http.Request) (*model.User, error) {
	user := model.User{}
	err := db.Get(&user, queries.QueryFindUser, id) // <----- Here
	return &user, err
}

If I use QueryFindUser (capital first letter) then it will become exportable to all the other packages. But I don't want this to be accessible by say config/config.go

I want it to be restricted to handler's modules only exlcluding the model/model.go.

If I declare queryFindUser this will be limited to the package queries only and then I won't be able to use it anywhere.

How to solve this thing? Without making it exportable to every other package.
I am quite new to golang/java and this issue will be same in java as well.
So what to do in this case?
If you can provide resources that will also be helpful to me.

答案1

得分: 1

访问标识符的权限并不是非常精细,你无法指定授予访问权限的对象。而且也没有必要这样做。这样做只会不必要地增加使用(源代码)和实现(编译时间、编译包对象和可执行二进制文件大小)的复杂性。

如果你只想给一个特定的包访问权限,最简单的方法是合并这些包并将标识符设为非导出。

如果你想给多个包或者包会变得非常庞大,你可以使用内部包。内部包的引入使得你可以将“大”包拆分为多个较小的包,同时仍然可以隐藏和保护实现细节,使其对“外部”(其他包)不可见。

内部包可以定义导出的标识符,但只允许“内部组”访问它们。

例如:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── internal
│   │   │   ├── queries
│   │   │   │   └── queries.go
│   │   │   └── foo
│   │   │       └── foo.go
│   │   ├── users.go
│   │   ├── common.go
│   │   └── users.go
│   └── model
│       └── model.go
├── config
│   └── config.go
└── main.go

在这个例子中,queries包可以被handler包和foo包访问,但不能被model包或config包访问。

一般来说,内部包(位于路径中具有internal文件夹的文件夹内的包)只能从父级internal文件夹的根目录下的包中导入。

参考相关问题:

https://stackoverflow.com/questions/45899203/can-i-develop-a-go-package-in-multiple-source-directories/45902409#45902409

https://stackoverflow.com/questions/59342373/use-of-internal-package-not-allowed/59342483#59342483

英文:

Access permission to identifiers is not so fine grained that you can specify who you're granting access. And there's no need. This would unnecessarily complicate both the uses (source code) and the implementation (compilation time, compiled package object and executable binary size).

If you want to give access to a specific package only, easiest is to merge the packages and make the identifiers unexported.

If you want to give access to multiple packages or the package would get unpleasantly big, you may use internal packages. Internal packages were introduced so you can break "big" packages into multiple, smaller ones, and still keep the implementation detail hidden and protected from the "outside" (from other packages).

Internal packages may define exported identifiers, but access to them is only allowed to the "internal group".

For example:

├── app
│   ├── app.go
│   ├── handler
│   │   ├── internal
│   │   │   ├── queries
│   │   │   │   └── queries.go
│   │   │   └── foo
│   │   │       └── foo.go
│   │   ├── users.go
│   │   ├── common.go
│   │   └── users.go
│   └── model
│       └── model.go
├── config
│   └── config.go
└── main.go

In this example the queries package is accessible by the handler package and by the foo package, but is not accessible by the model or config packages.

In general, internal packages (packages that are inside a folder that has an internal folder in their path) can only be imported from packages rooted at the parent of the internal folder.

See related questions:

https://stackoverflow.com/questions/45899203/can-i-develop-a-go-package-in-multiple-source-directories/45902409#45902409

https://stackoverflow.com/questions/59342373/use-of-internal-package-not-allowed/59342483#59342483

huangapple
  • 本文由 发表于 2022年6月1日 20:14:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/72461734.html
匿名

发表评论

匿名网友

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

确定