How do you want to use these pointers? You can only get a pointer to a variable, because it allows you to modify the underlying value. A literal is a constant expression, so the compiler doesn’t allow you to get a pointer to it.
Note that in your last example a and b are pointers to copies of "test" and 20. That is because you first pass those literals by value to P. The value is copied to t and then the pointer to t, not the actual function argument, is returned.
Because you are not getting a pointer to the literal anyway. Function Ptr first instantiates a (local) variable v from the literal and then returns the pointer to that variable (which probably escapes to the heap because of it, BTW).
There simply is no gain from this operation. Use pointers for their stated purposes in Go: passing by reference when you need to modify something in a function or, in rare cases, to reduce the cost of copying large data structures.
I know the compiler won’t allocate memory for the number 30, so I have to declare the age variable explicitly to get a pointer. Thus instantiating a (local) variable v from the literal is OK for this case.
Second, there is some logic for each field in UserQuery to do only when they are not assigned. So I have to use pointers in the struct to check if the value is nil instead of 0 or empty string.
Thank you Leo for your information, I’m making a framework based on go 1.18 which is the first version to support generic types, and I didn’t know the new feature in 1.22 before.
I checked the new feature, I think they can provide a similar effect but not exactly the same. With
type Null[T any] struct {
V T
Valid bool
}
the UserQuery would be
type UserQuery struct {
Age sql.Null[int]
MemoNull sql.Null[bool]
}
and check if the fields are assigned by checking sql.Null.Valid, right?
This provides the same effect by checking if the pointer is nil in previous code.
But I think this brings some side effects. It takes more memory to create such a struct first, and it’s also a pain for the JSON package to do (de)serialization, as well as reflective creation.
It’s not true. Your solution with pointers actually requires more memory than this one. Through the discussion some of your answers looked like you treat pointer as a value. But it’s a pointer and your actual value is still somewhere in memory. So, since a struct doesn’t create memory overhead and it’s size is the sum of sizes of the fields. Thus, for example, Null[string] will require 8+1 bytes. At the same time, pointer has a fixed sizes, 4 bytes on 32-bit and 8 bytes on 64-bit. Since x64 is more common, your solution with *string will require 8+8 bytes.
Marshal/Unmarshal are interfaces. You can always implement your own solution for those values, but it’s not a unique thing. There are tons of packages out there, to do it for you. Check this one for example.
Well, at the times I was learning golang, a very smart person told me:
if you are using reflection, you are doing something wrong.
In what world there might be a need to create a struct with pointers with reflect package to use it in sql?! But okay, if it’s actually a need, you can get the value of a string and create Null by yourself. Most part of the time there are no super-duper easy one-line solutions in go. The package, I sent above, already has functions to create its types.
Thanks for the pointer knowledge, Leo, but I think you forgot the memory alignment for the bool in sql.Null. Null[string] will require 8+8 bytes instead of 8+1. And I knew the value assigned to the pointer would require extra bytes.
In my PC, string requires 16 bytes.
So UserQuery3 will always require 40 bytes, while UserQuery4 requires 16 bytes when all pointers are nil and 40 bytes at most when all fields are assigned.
For most cases, less than half of the struct will be assigned, that’s what I mean by it takes more memory to create UserQuery3.
For JSON data, it will require an extra implementation or package to introduce complexity.
For reflection, what I make is a framework to process the structs defined by users with arbitrary fields, as far as I know, there is no other way to get the field names except reflection.