How to differentiate int null and defaulted to zero from int actually equal to zero? - go

I am a long time python user moving to Go, and I still have some issues to reacquire basic skill to manage typing and pointer.
I have a program receiving event from RabbitMq (But the problem would be the same no matter what transport we are talking about). One of the even contain an optional field F1 typed as int.
My understanding is, if the field is not present in the event, then go will default it to 0. But 0 is a valid value for that field, and I need to differentiate cases where the value is 0, and cases where the value is non defined.
I thought to make my field a *int to actually have "nil" as a value. But then when when a receive an event, will F1 be set to the actual pointed value, or the value address from the sender?
Do I have any other alternative?

In most cases, using a pointer to the value makes sense. E.g
type RabbitMessage struct {
F1 *int `json:"f1"`
}
The exact details of how this will work depends on how you serialise your data before sending it over RabbitMQ. If you are using JSON, then there should be no issue with this as both a null value, and an omitted value, will be represented in Go as nil. When the value is provided, it will be set to the value you expect (it will not use the address from the sender).

If you control only the receiver program, then AFAICT you can not differentiate between an int that has been automatically initialized to 0 by go from an int that has been set to 0 by the sender.
If you can modify the sender program though, an alternative could be to add a boolean field along with your int, telling whether the int is set or not. Then on the receiving end you can check whether the boolean is true or not.
You can also send a pointer to an int:
type Message struct {
Value *int `json:"value"`
}
message := Message{Value: 4}
Be aware though that when unmarshalling this you'll get an int pointer you'll need to dereference.

"Do I have any other alternative?" -- Yes, you can define a custom type, similar to sql.NullInt64.
type OptionalInt struct {
Int int
IsValid bool
}
func NewOptionalInt(i int) OptionalInt {
return OptionalInt{Int: i, IsValid: true}
}
func (o *OptionalInt) UnmarshalJSON(data []byte) error {
if string(data) != "null" {
if err := json.Unmarshal(data, &o.Int); err != nil {
return err
}
o.IsValid = true
}
return nil
}
func (o OptionalInt) MarshalJSON() ([]byte, error) {
if o.IsValid {
return json.Marshal(o.Int)
}
return json.Marshal(nil)
}

Related

assert interface{} to int64

i am using gin, i use c.shouldBind to bind the data to the struct, the use c.set to set the params in the context. when i use c.getInt64 to get the params, it can't return the value i set in the context(i set a 1), it return a zero. it failed to assert a float64 1 to a int64 0.
i have google it but can't get the answer i want
here are my debug code
// GetInt64 returns the value associated with the key as an integer.
func (c *Context) GetInt64(key string) (i64 int64) {
if val, ok := c.Get(key); ok && val != nil {
i64, _ = val.(int64)
}
return
}
the val is 1, but it returns 0
So can anybody tell me why and how to solve it.
Golang can't convert types implicitly. You can use the GetFloat64 method.
It depends the value which you really set in, and check the key is right, After that, Maybe you could use assertion after Get like: value := c.Get("From_validator_page").(Int64)

How to use non-nullable indices and 0-indexed lists

If I'm passing an int value in a struct (in my particular case, rpc arguments), the language does not allow the attribute to be nil. The empty value for an int is 0.
But Go uses 0-indexed arrays. I need a way to differentiate between an empty value and an index of 0. Is there an idiomatic go solution for this problem?
// this is psuedo-code I had written before hitting this problem
if (args.maybeIndex != nil) {
doSomething(sliceOfNodes[args.maybeIndex])
}
If you encode your ints by value, then there's not much you can do about it - the default value is 0.
A common way to ensure nullability in encodings in Go is to use pointer types. Using a *int instead of an int lets you distinguish between "none" and 0.
E.g. with a JSON example, consider the struct:
type Options struct {
Id *string `json:"id,omitempty"`
Verbose *bool `json:"verbose,omitempty"`
Level *int `json:"level,omitempty"`
Power *int `json:"power,omitempty"`
}
And this data:
{
"id": "foobar",
"verbose": false,
"level": 10
}
Note that "power" is not specified. You could write a deserializer:
func parseOptions(jsn []byte) Options {
var opts Options
if err := json.Unmarshal(jsonText, &opts); err != nil {
log.Fatal(err)
}
if opts.Power == nil {
var v int = 10
opts.Power = &v
}
return opts
}
That sets a default value to "power", if it's not specified. This lets you distinguish between "power was not present" and "power was present and its value was 0".
If your encoding / RPC mechanism does not permit pointers, you could work around this by having another boolean field called "index present" or something like this.
Finally, consider designing your program to make it resilient to the difference between "not set" and "set to default value". IOW, just accept that default values and unspecified data are one and the same. In the long term, this will result in a cleaner design and code, and will be less error prone.

Check if struct field is empty

I would like to iterate over the fields of a struct after unmarshalling a JSON object into it and check for the fields whose value was not set (i.e. are empty).
I can get the value of each field and compare that to the reflect.Zero value for the corresponding type
json.Unmarshal([]byte(str), &res)
s := reflect.ValueOf(&res).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
v := reflect.ValueOf(f.Interface())
if (reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())) {
....
But the problem, of course, is that this will not work well for bool or int values.
If a bool field is set to false in the JSON or an int field is set to 0, they will be equal to the zero value of their type. The aforementioned check will consider the fields to be uninitialized, even though they actually have a value set.
I know one way around this is to use pointers, but I just don't see how that would be possible in this case as I'm working with reflect.Value types, not the actual struct.
As you've mentioned, you could use pointers.
The json package can handle unmarshalling values into pointers for you. You've not included the json payload you are trying to unmarshal, or the struct you are unmarshalling into, so I've made up an example.
// json
{
"foo": true,
"number_of_foos": 14
}
// go struct
type Foo struct {
Present bool `json:"foo"`
Num int `json:"number_of_foos"`
}
Here if the keys foo or number_of_foos is missing, then as you've correctly observed, the zero value (false/ 0) will be used. In general the best advice is to make use of the zero value. Create structures so that zero values of false are useful, rather than a pain.
This is not always possible, so changing the types of the fields in the Foo struct to be pointers will allow you to check the 3 cases you are after.
Present
Present and zero
Missing
here is the same struct with pointers:
// go struct
type Foo struct {
Present *bool `json:"foo"`
Num *int `json:"number_of_foos"`
}
Now you can check for presence of the value with fooStruct.Present != nil and if that condition holds, you can assume that the value in the field is the one you wanted.
There is no need to use the reflect package.
Another way of doing the same is by implementing json.Unmarshaler.
type MaybeInt struct {
Present bool
Value int
}
func (i *MaybeInt) UnmarshalJSON(bs []byte) error {
if e := json.Unmarshal(bs, &i.Value); e != nil {
return e
}
i.Present = true
return nil
}
You can then use MaybeInt in your top-level structure:
type Top struct {
N MaybeInt `json:"n"`
M MaybeInt `json:"m"`
}
func main() {
t := Top{}
if e := json.Unmarshal([]byte(` { "n": 4930 } `), &t); e != nil {
panic(e)
}
fmt.Println(t.N, t.M)
}
See it working on the playground
Try using the golang validator package. The validator package offers a required attribute that might do the required job for your need. The official documentation for required attribute states:
This validates that the value is not the data types default zero value. For numbers ensures value is not zero. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil.
The example illustrating the same can be seen at: https://github.com/go-playground/validator/blob/v9/_examples/struct-level/main.go.
Hope this solves your requirement.

Type assertion when returning an interface

I'm new to golang; however based on my current knowledge I understand that a value-type and a reference-type can both fulfill an interface. But it seems in regards to type assertion, how you return a struct does matter. See the following:
package main
import (
"fmt"
)
type SomeError interface {
Error() string
}
type ConcreteError struct{}
func (ConcreteError) Error() string {
return "?"
}
func returnPointer() SomeError {
return &ConcreteError{}
}
func returnVal() SomeError {
return ConcreteError{}
}
func main() {
pointer := returnPointer()
value := returnVal()
_, pointerWithPointer := pointer.(*ConcreteError);
_, pointerWithValue := pointer.(ConcreteError);
_, valueWithValue := value.(ConcreteError);
_, valueWithPointer := value.(*ConcreteError)
fmt.Printf("Returning a pointer, assert using (*ConcreteError): %v\n", pointerWithPointer); // true
fmt.Printf("Returning a pointer, assert using (ConcreteError): %v\n", pointerWithValue); // false
fmt.Printf("Returning a value, assert using (ConcreteError): %v\n", valueWithValue); // true
fmt.Printf("Returning a value, assert using (*ConcreteError): %v\n", valueWithPointer); // false
}
So if my understanding is correct, the user needs to know how the struct is returned to correctly assert its type?
I'm going to guess and assume the standard practice in golang is to always return a pointer to a struct(i.e like *PathError)?
link to play: here
So if my understanding is correct, the user needs to know how the struct is returned to correctly assert its type?
It depends. If you need the type assertion to pass - you surely need to know the exact type of the value. a and *a are different types.
I'm going to guess and assume the standard practice in golang is to always return a pointer to a struct(i.e like *PathError)?
No.

How to resolve whether pass objects via interface{} have not initializated fields

I have problem with resolve whether object which was pass as interface to function hasn't initializated fields, like object which was defined as just someObject{} is a empty, because all fields, has value 0, or nil
Problem becomes more complicated if I pass diffrent objects, because each object have diffrent type field value so on this moment I don't find universal way to this.
Example
func main(){
oo := objectOne{}
ot := objectTwo{}
oth := objectThree{"blah" , "balbal" , "blaal"}
resolveIsNotIntialized(oo)
resolveIsNotIntialized(ot)
resolveIsNotIntialized(oth)
}
func resolveIsNotIntialized(v interface{}) bool{
// and below, how resolve that oo and ot is empty
if (v.SomeMethodWhichCanResolveThatAllFiledIsNotIntialized){
return true
}
return false
}
I want to avoid usage switch statement like below, and additional function for each object, ofcorse if is possible.
func unsmartMethod(v interface{}) bool{
switch v.(type){
case objectOne:
if v == (objectOne{}) {
return true
}
// and next object, and next....
}
return false
}
As Franck notes, this is likely a bad idea. Every value is always initialized in Go. Your actual question is whether the type equals its Zero value. Generally the Zero value should be designed such that it is valid. The better approach would generally be to create an interface along the lines of:
type ZeroChecker interface {
IsZero() bool
}
And then attach that to whatever types you want to check. (Or possibly better: create an IsValid() test instead rather than doing your logic backwards.)
That said, it is possible to check this with reflection, by comparing it to its Zero.
func resolveIsNotIntialized(v interface{}) bool {
t := reflect.TypeOf(v)
z := reflect.Zero(t).Interface()
return reflect.DeepEqual(v, z)
}
(You might be able to get away with return v == z here; I haven't thought through all the possible cases.)
I don’t think there is a good reason (in idiomatic Go) to do what you are trying to do. You need to design your structs so that default values (nil, empty string, 0, false, etc.) are valid and represent the initial state of your object. Look at the source of the standard library, there are lots of examples of that.
What you are suggesting is easily doable via Reflection but it will be slow and clunky.
You could narrow the type which your function takes as an argement a little, not take an interface{} but accept one that allows you to check for non-zero values, say type intercae{nonZero() bool} as in the example code below. This will not tell you explicitly that it hasn't been set to the zero value, but that it is not zero.
type nonZeroed interface {
nonZero() bool
}
type zero struct {
hasVals bool
}
func (z zero) nonZero() bool {
return z.hasVals
}
type nonZero struct {
val int
}
func (nz nonZero) nonZero() bool {
return nz.val != 0
}
type alsoZero float64
func (az alsoZero) nonZero() bool {
return az != 0.0
}
func main() {
z := zero{}
nz := nonZero{
val: 1,
}
var az alsoZero
fmt.Println("z has values:", initialized(z))
fmt.Println("nz has values:", initialized(nz))
fmt.Println("az has values:", initialized(az))
}
func initialized(a nonZeroed) bool {
return a.nonZero()
}
Obviously as the type get more complex additional verification would need to be made that it was "nonZero". This type of pattern could be used to check any sort condition.

Resources