英文:
Saving enumerated values to a database
问题
我是你的中文翻译助手,以下是翻译好的内容:
我刚开始学习Go语言,尝试编写一个小程序将枚举值保存到数据库中。
我声明值的方式如下:
type FileType int64
const (
movie FileType = iota
music
book
etc
)
我在结构体中使用这些值,如下所示:
type File struct {
Name string
Type FileType
Size int64
}
我使用gorp来处理数据库操作,但我想这与我的问题无关。我将数据存入数据库的方式如下:
dbmap.Insert(&File{"MyBook.pdf", movie, 1000})
但是当我尝试检索数据时...
dbmap.Select(&dbFiles, "select * from Files")
我遇到了以下错误:
panic: reflect.Set: value of type int64 is not assignable to type main.FileType
当我将const(...)
和File.Type
字段的类型设置为int64
时,一切正常,但我刚开始学习Go语言,想要理解这个问题。
在我看来,我有两个问题:
-
为什么Go无法成功转换这些值?我查看了Go反射和SQL包的源代码,发现有一些用于此类转换的方法,但它们似乎失败了。这是一个bug吗?问题出在哪里?
-
我发现可以通过实现
sql.Scanner
接口来解决问题,只需实现以下方法:Scan(src interface{}) error
我尝试实现这个方法,甚至能够从
src
中获取正确的值并将其转换为FileType
,但我对于应该为"(f *FileType)
"还是"(f FileType)
"实现该方法感到困惑。无论哪种方式,该方法都会被调用,但我无法更新f
(或者至少更新后的值会丢失),从数据库中读取的File
实例的File.Type
始终为"0"。
对于这两个问题,你有什么想法吗?
英文:
I'm new to Go and I'm trying to write a little program to save enumerated values to a database.
The way I declare my values is as follows:
type FileType int64
const (
movie FileType = iota
music
book
etc
)
I use these values in my struct like this:
type File struct {
Name string
Type FileType
Size int64
}
I use gorp for my database stuff, but I guess the use of gorp isn't relevant to my problem. I put stuff in my DB like this:
dbmap.Insert(&File{"MyBook.pdf",movie,1000})
but when I try to retrieve stuff…
dbmap.Select(&dbFiles, "select * from Files")
I get the following error:
panic: reflect.Set: value of type int64 is not assignable to type main.FileType
When I use int64
as the type for the const(...)
and for the File.Type
field, everything works fine, but I'm new to Go and want to understand the problem.
The way I see it, I have two problems:
-
Why can't Go convert this stuff successfully? I looked at the source code of the Go reflection and sql packages and there are methods for this kind of conversion, but they seem to fail. Is this a bug? What is the problem?
-
I figured out, that one can implement the
sql.Scanner
interface by implementing the following method:Scan(src interface{}) error
I tried to implement the method and I even was able to get the right value from src
and convert it to a FileType
, but I was confused if I should implement the method for "(f *FileType)
or (f FileType)
. Either way the method gets invoked, however I'm not able to overwrite f
(or at least the update gets lost later) and the File
instances read from the DB always had a "0" as value for File.Type
.
Do you have any ideas on those two points?
答案1
得分: 29
我最近也有同样的需求,解决方案是实现两个接口:
下面是一个可行的示例:
type FileType int64
func (u *FileType) Scan(value interface{}) error { *u = FileType(value.(int64)); return nil }
func (u FileType) Value() (driver.Value, error) { return int64(u), nil }
希望对你有帮助!
英文:
I recently had the same need, and the solution is to implement two interfaces:
Here's a working example:
type FileType int64
func (u *FileType) Scan(value interface{}) error { *u = FileType(value.(int64)); return nil }
func (u FileType) Value() (driver.Value, error) { return int64(u), nil }
答案2
得分: 9
略微偏离主题,但对于其他人可能会有用,因为我在解决类似问题时一直在查看这个问题/答案,这个问题是在使用golang处理postgres枚举字段时遇到的(它们以字节形式返回)。
// 状态值
const (
incomplete Status = "incomplete"
complete Status = "complete"
reject Status = "reject"
)
type Status string
func (s *Status) Scan(value interface{}) error {
asBytes, ok := value.([]byte)
if !ok {
return errors.New("Scan source is not []byte")
}
*s = Status(string(asBytes))
return nil
}
func (s SubjectStatus) Value() (driver.Value, error) {
// 验证将在此处进行
return string(s), nil
}
英文:
Slightly off-topic, but may be useful to others as I kept revisiting this question/answer when solving a similar problem when working with postgres enum fields in golang (which are returned as bytes).
// Status values
const (
incomplete Status = "incomplete"
complete Status = "complete"
reject Status = "reject"
)
type Status string
func (s *Status) Scan(value interface{}) error {
asBytes, ok := value.([]byte)
if !ok {
return errors.New("Scan source is not []byte")
}
*s = Status(string(asBytes))
return nil
}
func (s SubjectStatus) Value() (driver.Value, error) {
// validation would go here
return string(s), nil
}
答案3
得分: 0
- Go需要对类型进行具体说明,有时候这可能会很麻烦。
- 对于“原生”类型来说,
(f FileType)
比(f *FileType)
更加高效,除非你有一个复杂的类型,否则通常最好不要使用指针。 - 你说的它不会覆盖它是什么意思?你在修改结构体后是否重新保存了它?
英文:
- Go needs to be specific with types, which can be a pain sometimes.
(f FileType)
is cheaper than(f *FileType)
for "native" types, pretty much unless you have a complex type, it's almost always better to not use a pointer.- What do you mean it doesn't overwrite it? did you resave the struct after you modified it?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论