2

I usually like to use pointers for primitive data types in my structs so that when I json.Marshal them, the nil fields are always translated to "field": null in the json string. But this will make it difficult to create a new struct instance since I can't use literals.
For example:

type Book struct {
  Price *float32 `json:"price"`
  Title *string `json:"title"`
  Author *string `json:"author"`
}

func main() {
    // I can't do this
    book := &Book{
        Title: "Book1",
    }
}

As you can see, when I use a string pointer, I can't initialise a struct easily unless I declare a variable for each pointer field and assign them to the struct fields. Is it possible to have both nullable json fields and the ease of initialising structs without declaring extra variables?

icza
  • 389,944
  • 63
  • 907
  • 827

2 Answers2

3

Add a helper function to your app:

func NewString(s string) *string {
    return &s
}

And then you can use literals:

// You can do this:
book := &Book{
    Title: NewString("Book1"),
}

There are also libraries providing these NewXXX() functions so you don't have to add them (e.g. github.com/icza/gox/gox, disclosure: I'm the author).

See related: How do I do a literal *int64 in Go?

icza
  • 389,944
  • 63
  • 907
  • 827
  • The answers in the related question are all hacky in some way. I wish Go had a builtin way of doing this but seems like this can be achieved only with wrapper functions like your package does. Thanks a lot! – Kashif Minhaj Feb 06 '20 at 05:29
  • Also, I'd be curious to know the memory / performance impacts of doing this with a function returning pointer? – Kashif Minhaj Feb 06 '20 at 05:32
  • @KashifMinhaj Performance impact likely "nothing" as it will be inlined. Memory impact? It allocates a string on the heap, just like `new(string)` would do. But nothing more. You can't solve this with less than that. – icza Feb 06 '20 at 07:53
2

There are some problem with your initialization:

  • type Books is not a valid way to declare a struct (fixed)

  • You are trying to assign a plain string to a pointer

Example solution:

type Book struct {
    Price  *float32 `json:"price"`
    Title  *string  `json:"title"`
    Author *string  `json:"author"`
}

func main() {
    bookTitle := "Book1"
    // I can't do this
    book := &Book{
        Title: &bookTitle,
    }
}

Another approach for solve the problem, is to create a Constructor:

type Book struct {
    Price  *float32 `json:"price"`
    Title  *string  `json:"title"`
    Author *string  `json:"author"`
}

func (b *Book) Book(title string){
    b.Title = &title    
}


func main() {
    var book Book
    fmt.Printf("%+v\n", book)
    book.Book("Book1")
    fmt.Printf("%+v\n", book)
}

The result will be something like this:

{Price:<nil> Title:<nil> Author:<nil>}
{Price:<nil> Title:0xc00003e1f0 Author:<nil>}
alessiosavi
  • 2,753
  • 2
  • 19
  • 38
  • Sorry for the typo in declaring struct, it has been edited by @icza Thanks! Declaring a constructor like you suggested is not ideal since I'd want to set only some of the fields. I'd have to write multiple constructor methods to achieve that. – Kashif Minhaj Feb 06 '20 at 05:25