简体   繁体   中英

Initialize a nil pointer struct in method

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)
}

Playground

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM