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?

0

2 Answers 2

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?

Sign up to request clarification or add additional context in comments.

3 Comments

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!
Also, I'd be curious to know the memory / performance impacts of doing this with a function returning pointer?
@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.
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>}

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.