I have a struct called Article
which has a field called Image
. Per default Image
has value nil
. As Image
should be only persisted as Image.Id
to database I use the bson.BSONGetter
, bson.BSONSetter
and json.Marshaler
interfaces to fake this behavior.
However internally it is possible to use Image
as an io.ReadWriteCloser
if I load a file onto this with some other helper.
package main
import (
"io"
"fmt"
"gopkg.in/mgo.v2"
)
type Article struct {
Name string
Image *Image
}
type Image struct {
Id interface{}
io.ReadWriteCloser
}
func (i *Image) SetBSON(r bson.Raw) error {
i = &Image{}
return r.Marshal(i.Id)
}
func (i *Image) GetBSON() (interface{}, error) {
return i.Id
}
func (i *Image) MarshalJSON() ([]byte, error) {
return json.Marshal(i.Id)
}
The problem with this approach now is that it is not possible to initialize Image
in Image.SetBSON
as Image
is nil
.
The receiver is passed by value , including the pointer receiver: it is a copy, and changing its value doesn't change the initial pointer receiver on which the method is called.
See " Why are receivers pass by value in Go? ".
A function Setup
returning a new *Foo would work better: play.golang.org
func SetUp() *Foo {
return &Foo{"Hello World"}
}
func main() {
var f *Foo
f = SetUp()
}
Output:
Foo: <nil>
Foo: &{Bar:Hello World}
twotwotwo points to a better convention in the comments , which is to make a package function foo.New()
, as in sha512.New()
.
But here, your Setup()
function might do more than just creating a *Foo
.
bson.Unmarshal
creates a pointer to an Image
value when it comes across it in the bson data. So once we enter SetBSON
i
is already a valid pointer to an Image
struct. That means that there is no reason for you to allocate the Image
.
package main
import (
"fmt"
"io"
"gopkg.in/mgo.v2/bson"
)
type Article struct {
Name string
Image *Image `bson:"image,omitempty"`
}
type Image struct {
Id interface{}
AlsoIgnored string
io.ReadWriteCloser
}
func (i *Image) SetBSON(r bson.Raw) error {
err := r.Unmarshal(&i.Id)
return err
}
func (i Image) GetBSON() (interface{}, error) {
return i.Id, nil
}
func main() {
backAndForth(Article{
Name: "It's all fun and games until someone pokes an eye out",
Image: &Image{
Id: "123",
AlsoIgnored: "test",
},
})
backAndForth(Article{Name: "No img attached"})
}
func backAndForth(a Article) {
bsonData, err := bson.Marshal(a)
if err != nil {
panic(err)
}
fmt.Printf("bson form: '%s'\n", string(bsonData))
article := &Article{}
err = bson.Unmarshal(bsonData, article)
if err != nil {
panic(err)
}
fmt.Printf("go form : %#v - %v\n", article, article.Image)
}
http://play.golang.org/p/_wb6_8Pe-3
Output is:
bson form: 'Tname6It's all fun and games until someone pokes an eye outimage123'
go form : &main.Article{Name:"It's all fun and games until someone pokes an eye out", Image:(*main.Image)(0x20826c4b0)} - &{123 <nil>}
bson form: 'nameNo img attached'
go form : &main.Article{Name:"No img attached", Image:(*main.Image)(nil)} - <nil>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.