What is the default value of a map of struct - go

What is the default value of struct in a map? How to check the map value is initialized?
type someStruct struct {
field1 int
field2 string
}
var mapping map[int]someStruct
func main() {
mapping := make(map[int]someStruct)
}
func check(key int) {
if mapping[key] == ? {}
}
Should I check against nil or someStruct{}?

Default value of a struct is zero value for each field which is different on basis of its type.
When storage is allocated for a variable, either through a
declaration or a call of new, or when a new value is created, either
through a composite literal or a call of make, and no explicit
initialization is provided, the variable or value is given a default
value. Each element of such a variable or value is set to the zero
value for its type: false for booleans, 0 for numeric types, "" for
strings, and nil for pointers, functions, interfaces, slices,
channels, and maps. This initialization is done recursively, so for
instance each element of an array of structs will have its fields
zeroed if no value is specified.
type T struct { i int; f float64; next *T }
t := new(T)
the following holds:
t.i == 0
t.f == 0.0
t.next == nil
But for checking the value of a map based on the key if it exists you can use it as:
i, ok := m["route"]
In this statement, the first value (i) is assigned the value stored under the key "route". If that key doesn't exist, i is the value type's zero value (0). The second value (ok) is a bool that is true if the key exists in the map, and false if not.
For your question
Should I check against nil or someStruct{} ?
To check for initialized empty struct you can check for someStruct{} as:
package main
import (
"fmt"
)
type someStruct struct {
field1 int
field2 string
}
var mapping map[int]someStruct
func main() {
var some someStruct
fmt.Println(some == (someStruct{}))
//mapping := make(map[int]someStruct)
}
Go playground

Related

Is there a way to set a pointer struct field to a pointer pointing to the Zero value of that pointer type using reflect?

That was a mouthful of a title, let me explain more. Assuming I have a struct of all pointers (don't know of what type)
type A struct {
S *string
I *int
}
I want to write a function that takes a pointer to that struct and given a fieldName sets that field to a pointer to the Zero/empty value of that pointer. For example:
func setZeroForField(i any, fieldName string) {
// do stuff
}
a := A{}
setZeroForField(&a, "S")
setZeroForField(&a, "I")
// *a.S == ""
// *a.I == 0
Is there any way to do it using reflect? I know how to get the types of the fields of A but I can't use reflect.Indirect because it just returns a Zero value which in this case is a nil pointer, not the empty string or 0.
func setZeroForField(i any, fieldName string) {
rv := reflect.ValueOf(i).Elem()
fv := rv.FieldByName(fieldName)
fv.Set(reflect.New(fv.Type().Elem()))
}
https://go.dev/play/p/7clmztF5uaa

How to get a Protobuf enum value from its string representation?

I can get the string value of a Protobuf enum with this instruction:
str := testPB.Status_ENABLED.String()
How can I perform the inverse operation? (from a string, get the enum element).
The generated code has a map called <EnumName>_value of type map[string]int32. Then you can convert the numerical value to the actual defined type:
num := testPB.Status_value[str]
v := testPB.Status(num)
Consider that if the str value doesn't exist in the map (note that it's case sensitive), the map look-up will return 0. Depending on how you defined your protobuffer, the 0 value might be mapped to a an enum instance that does not have "zero" semantics. This is why it is recommended to map 0 to an "unknown" instance:
enum Status {
UNKNOWN = 0;
ENABLED = 1;
// and so on
}
Which in Go correctly yields a makeshift zero-value if the string representation is effectively unknown:
v := testPB.Status(testPB.Status_value["does_not_exist"])
fmt.Println(v == testPB.Status_UNKNOWN) // true
Go 1.18
With generics, it is possible to write reusable code to construct protobuffer enums from string values:
func Enum[T ~string, PB ~int32](val T, pbmap map[string]int32, dft PB) PB {
v, ok := pbmap[string(val)]
if !ok {
return dft
}
return PB(v)
}
where:
the type parameter T is the string representation, which could also be a type with underlying type string, e.g. type MyEnum string
the argument pbmap is the <EnumName>_value from the generated protobuffer code
the type parameter PB is the protobuffer enum type.
The function above takes a default value of type PB to (obviously) have a fallback in case the string representation is invalid, and also to allow type inference on PB, which otherwise would be used only as a return type.
Usage:
type SomeEnum string
const (
SomeEnumFoo SomeEnum = "FOO"
SomeEnumBar SomeEnum = "BAR"
)
func main() {
foo := SomeEnumFoo
v := Enum(foo, pb.SomeEnum_value, pb.SomeEnum_Foo)
// ^ T ^ map[string]int32 ^ default PB value
// v is type pb.SomeEnum
}

How can I set null value as default to struct

I am trying to add null value as default to struct. Is there any way to add null as default?
type Values struct {
FirstValue string `default:"My First Value"`
SecondValue string `default:nil` // something like that
}
Strings in Go cannot be nil. Their zero value is just an empty string - "".
See https://tour.golang.org/basics/12
Also, there is no default tag in Go as each type has a zero value which is used as a "default". But, there are patterns in Go that allow you to set different "default" values, see How to set default values in Go structs.
In Go you can't access uninitialized memory. If you don't provide an initial value in a variable declaration, the variable will be initialized to the zero value of its type automatically.
Moreover, you can't define default values for struct fields. Unless given with a composite literal, all fields will get their zero values.
Zero value of the string type is the empty string "". If you need to store the null value, use a pointer to string. Zero value for pointers is nil:
type Values struct {
FirstValue string
SecondValue *string
}
maybe try this way :)
package main
import (
"encoding/json"
"fmt"
)
type Hoho struct {
Name *string `json:"name"`
}
func main() {
var nama string = "ganang"
var h Hoho
h.Name = NullString(nama)
wo, _ := json.Marshal(h)
fmt.Print(string(wo))
}
func NullString(v string) *string {
if v == "" {
return nil
}
return &v
}

What value does the return value take if something is not in a map?

Ok so according to this:
How to check if a map contains a key in go?
if val, ok := m["foo"]; ok {
//do something here
}
that's fine, but how come we can't do this:
val, ok := m["foo"]
if val == nil { // cannot compare val to nil
}
I get a compilation error saying I can't compare val to nil, but then what value does val have? What can I compare it to, to determine if it exists or not?
the type of m is like:
type m map[string]struct{}
The Go Programming Language Specification
Index expressions
For a of map type M: if the map is nil or does not contain such an
entry, a[x] is the zero value for the element type of M.
The zero value
When storage is allocated for a variable, either through a declaration
or a call of new, or when a new value is created, either through a
composite literal or a call of make, and no explicit initialization is
provided, the variable or value is given a default value. Each element
of such a variable or value is set to the zero value for its type:
false for booleans, 0 for numeric types, "" for strings, and nil for
pointers, functions, interfaces, slices, channels, and maps.
The Go Programming Language Specification
Composite literals
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key. For
struct literals the following rules apply:
A literal may omit the element list; such a literal evaluates to the
zero value for its type.
For your example, type struct{}, omit the element list from the composite literal, struct{}{}, for the zero value.
For example,
package main
import "fmt"
func main() {
m := map[string]struct{}{}
val, ok := m["foo"]
fmt.Printf("%T %v\n", val, val)
if val == struct{}{} {
fmt.Println("==", val, ok)
}
}
Playground: https://play.golang.org/p/44D_ZfFDA77
Output:
struct {} {}
== {} false
The Go Programming Language Specification
Variable declarations
A variable declaration creates one or more variables, binds
corresponding identifiers to them, and gives each a type and an
initial value.
If a list of expressions is given, the variables are initialized with
the expressions following the rules for assignments. Otherwise, each
variable is initialized to its zero value.
If a type is present, each variable is given that type. Otherwise,
each variable is given the type of the corresponding initialization
value in the assignment.
In your example, you could declare a variable of type struct{} with no initial value, which would be initialized to the zero value for the struct{} type.
For example,
package main
import "fmt"
func main() {
m := map[string]struct{}{}
val, ok := m["foo"]
fmt.Printf("%T %v\n", val, val)
var zeroValue struct{}
if val == zeroValue {
fmt.Println("==", val, ok)
}
}
Playground: https://play.golang.org/p/_XcSCEeEKJV
Output:
struct {} {}
== {} false
You can most certainly do what you did above. Comparing to nil depends on the type of value you have in map. If its interface{} you can compare it to nil:
m := map[string]interface{}{}
val, _ := m["foo"]
if val == nil {
fmt.Println("no index")
}

How to check if parameter passed into function is nil in Go?

Need to check if parameter being passed to func is nil and return 0.
Below is my intended code
func (t *Transaction) GetOperationCount(input bean.Request) (int, error) {
var result int = 0
if input == nil { //error here
return result, nil
}
// Other code here!!!!
return result, nil
}
bean.Reques is a struct.
However it had issue: "cannot convert nil to type bean.Request input Request". I have trying
if (bean.Request{})== input
But it gives :
"json:\"MV_STATUS\""; NDFNFFP string "json:\"NDF_NFFP\""; NDFNFMV string "json:\"NDF_NFMV\"" } "json:\"attr\"" } "json:\"marke
t_value\"" } "json:\"market_values\"" } "json:\"tick\"" } "json:\"insertion\"" } "json:\"operation\"" } "json:\"transaction\""
} cannot be compared)
Should I change the parameter to "input *bean.Request" ?
Short answer: Yes, here is the working version:
func (t *Transaction) GetOperationCount(input *bean.Request) (int, error) {
var result int = 0
if input == nil {
return result, nil
}
// Other code here
return result, nil
}
You have some options (depending to your use case, see: Pointers vs. values in parameters and return values):
1- You may use pointer (input *bean.Request) and compare it with nil
2- you may use another struct and compare it with reflect.DeepEqual(r, zero)
3- You may write your own compare function (or method with pointer or value receiver)
See this sample (try it on The Go Playground):
package main
import (
"fmt"
"reflect"
)
func (t *Transaction) GetOperationCount(input *Request) (int, error) {
var result int = 0
if input == nil {
return result, nil
}
// Other code here
return result, nil
}
func main() {
var input *Request
if input == nil {
fmt.Println("input is nil.") //input is nil.
}
input = &Request{}
if input != nil {
fmt.Println("input is not nil.") //input is not nil.
}
r := Request{}
fmt.Printf("Zero value: %#v\n", r) //Zero value: main.Request{I:0}
zero := Request{}
fmt.Println("r == zero :", r == zero) //r == zero : true
fmt.Println("DeepEqual :", reflect.DeepEqual(r, zero)) //DeepEqual : true
fmt.Println("compare :", compare(&r, &zero)) //compare : true
}
func compare(r, zero *Request) bool {
return r.I == zero.I
}
type Request struct {
I int
}
type Transaction struct{}
output:
input is nil.
input is not nil.
Zero value: main.Request{I:0}
r == zero : true
DeepEqual : true
compare : true
Comparison operators:
4- You may compare it with its zero value (nil for pointers, and if it is struct it's zero value is Empty struct if it is like struct{} (not nil), or struct with all fields initialized to their zero values):
The zero value:
When storage is allocated for a variable, either through a declaration
or a call of new, or when a new value is created, either through a
composite literal or a call of make, and no explicit initialization is
provided, the variable or value is given a default value. Each element
of such a variable or value is set to the zero value for its type:
false for booleans, 0 for integers, 0.0 for floats, "" for strings,
and nil for pointers, functions, interfaces, slices, channels, and
maps. This initialization is done recursively, so for instance each
element of an array of structs will have its fields zeroed if no value
is specified.
These two simple declarations are equivalent:
var i int
var i int = 0
After
type T struct { i int; f float64; next *T }
t := new(T)
the following holds:
t.i == 0
t.f == 0.0
t.next == nil
The same would also be true after
var t T
See "reflect.DeepEqual": How to compare struct, slice, map are equal?
func DeepEqual(x, y interface{}) bool
Docs:
DeepEqual reports whether x and y are ``deeply equal,'' defined as follows.
Two values of identical type are deeply equal if one of the following cases applies.
Values of distinct types are never deeply equal.
Array values are deeply equal when their corresponding elements are deeply equal.
Struct values are deeply equal if their corresponding fields,
both exported and unexported, are deeply equal.
Func values are deeply equal if both are nil; otherwise they are not deeply equal.
Interface values are deeply equal if they hold deeply equal concrete values.
Map values are deeply equal if they are the same map object
or if they have the same length and their corresponding keys
(matched using Go equality) map to deeply equal values.
Pointer values are deeply equal if they are equal using Go's == operator
or if they point to deeply equal values.
Slice values are deeply equal when all of the following are true:
they are both nil or both non-nil, they have the same length,
and either they point to the same initial entry of the same underlying array
(that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal.
Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil))
are not deeply equal.
Other values - numbers, bools, strings, and channels - are deeply equal
if they are equal using Go's == operator.
In general DeepEqual is a recursive relaxation of Go's == operator.
However, this idea is impossible to implement without some inconsistency.
Specifically, it is possible for a value to be unequal to itself,
either because it is of func type (uncomparable in general)
or because it is a floating-point NaN value (not equal to itself in floating-point comparison),
or because it is an array, struct, or interface containing
such a value.
On the other hand, pointer values are always equal to themselves,
even if they point at or contain such problematic values,
because they compare equal using Go's == operator, and that
is a sufficient condition to be deeply equal, regardless of content.
DeepEqual has been defined so that the same short-cut applies
to slices and maps: if x and y are the same slice or the same map,
they are deeply equal regardless of content.
Yes..The error itself mentions that it cannot compare both. You can use pointer to compare with nil or create an empty struct to compare.

Resources