A good way to make zero value meaningful - go

I have a struct with a int16 in it represent the offset of indexes in a slice. There are 2 states for this value: 1. it can be that the offset is invalid; 2. it's meaningful and will actually represent a positive, negative, or zero value offset. Now the question is that I will allocate an array of this struct, and the default value for this int16 should be the invalid state, but the default value is 0, and 0 can also represent a valid offset with value of 0.
Currently, I use -32768 as the value to represent the invalid state, and manually initialize the array after using make. However, I don't like this approach and it doesn't follow the Go way of making the zero value meaningful. Is there a better way to approach this? I don't really want to introduce extra variables as that will take more space in memory.

When accessing the offset value, you can remap the zero value to the invalid constant through addition and subtraction. This will require obscuring the type through a Get and Set, since accessing the internal value directly will no longer be valid.
package main
import "fmt"
type Offset struct {
// This value is not safe to use directly,
// since it has to be mapped to/from a real offset
mappedOffset int16
}
const InvalidOffset = -32768
func (o Offset) Get() int16 {
// Shift values so 0 becomes InvalidOffset
return o.mappedOffset + InvalidOffset
}
func (o *Offset) Set(i int16) {
// Shift values so InvalidOffset becomes 0
o.mappedOffset = i - InvalidOffset
}
func (o Offset) IsValid() bool {
// Check if it is the actual "Go Zero"
return o != Offset{}
}
func main() {
var offset Offset
fmt.Println("Apparent value:", offset.Get(), " Internal:", offset, " IsValid:", offset.IsValid())
offset.Set(123)
fmt.Println("Apparent value:", offset.Get(), " Internal:", offset, " IsValid:", offset.IsValid())
offset.Set(InvalidOffset)
fmt.Println("Apparent value:", offset.Get(), " Internal:", offset, " IsValid:", offset.IsValid())
}
Output:
Apparent value: -32768 Internal: {0} IsValid: false
Apparent value: 123 Internal: {-32645} IsValid: true
Apparent value: -32768 Internal: {0} IsValid: false

Found a solution. I can store it using an uint16 and offset it with math.minint16. This way the default value 0 is -32768 and is treated as the invalid state, all other numbers are valid.

Related

strconv.Itoa does not accept values of type int64

Im learning to create REST APIs using Go. Here's where I am stuck.
When user sends a CREATE request:
From the Slice of articles, I need to take the last article
Convert the ID(originally string) to Integer
Increment the Integer and convert it back to string and save it
Article Struct
type Article struct {
Id string `json:"id"`
Title string `json:"title"`
Desc string `json:"desc"`
Content string `json:"content"`
}
Here's the logic
// get the last id and convert it to integer and increment
lastId, err := strconv.ParseInt(Articles[len(Articles) - 1].Id, 10, 64)
lastId = lastId + 1
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
response := []Article{
{
Id: strconv.Itoa(lastId),// 👈 ERROR
Title: articleBody.Title,
Desc: articleBody.Desc,
Content: articleBody.Content,
},
}
ERROR
cannot use lastId (variable of type int64) as int value
in argument to strconv.Itoa compiler (IncompatibleAssign)
Go has a strong typing system so Int32 and Int64 are not compatible type. Try to convert lastId into an int when calling Itoa:
response := []Article{
{
Id: strconv.Itoa(int(lastId)),
Title: articleBody.Title,
Desc: articleBody.Desc,
Content: articleBody.Content,
},
}
Edit:
As mention by #kostix in his answer, beware of overflows when converting int type (see his answer for details).
A safer solution would be something like this:
newId := int(lastId)
if int64(newId) != lastId {
panic("overflows!")
}
response := []Article{
{
Id: strconv.Itoa(newId),
Title: articleBody.Title,
Desc: articleBody.Desc,
Content: articleBody.Content,
},
}
The language specification says:
uint either 32 or 64 bits
int same size as uint
This means, on a particular platform/version of Go int may be the same size as int32, and this is the reason why Go would not silently allow you to pass a value of type int64 as an argument of type int.
Moreover, a plain type conversion int(lastId) suggested in another answer should be taken with a grain of salt: what happens when your program is compiled and int ends up having 32 bits in size in the compiled code, and a particular lastId value is outside the number range supported by a signed 32-bit integer, say, 2,147,483,648?
Again, the spec says:
When converting between integer types, if the value is a signed integer, it is sign extended to implicit infinite precision; otherwise it is zero extended. It is then truncated to fit in the result type's size. For example, if v := uint16(0x10F0), then uint32(int8(v)) == 0xFFFFFFF0. The conversion always yields a valid value; there is no indication of overflow.
Hence the code
var i64 int64 = 2_147_483_648
var i32 = int32(i64)
fmt.Println(i32)
prints
-2147483648
And when this value is passed to strconv.Itoa, it returns "-2147483648" — quite possibly not what you would expect.
So, in a robust code, you ought to watch out when doing such type conversions, and either check the converted value for sanity, like in
v := int(lastId)
if int64(v) != lastId {
panic("ouch!")
}
or merely use the largest convenient type via strconv.FormatInt.

Why is a float64 type number throwing int related error in Go

I am trying to grasp Golang, in one of the tutorial example it says that An untyped constant takes the type needed by its context.
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
// Here Big is too large of a number but can be handled as a float64.
// No compilation error is thrown here.
fmt.Println(needFloat(Big))
// The below line throws the following compilation error
// constant 1267650600228229401496703205376 overflows int
fmt.Println(Big)
}
When calling fmt.Println(Big) why is Golang treating Big as an int where as by context it should be float64?
What am I missing?
What is the context for fmt.Println? In other words, what does fmt.Println expect Big to be? An interface{}.
From the Go Blog on Constants:
What happens when fmt.Printf is called with an untyped constant is that an interface value is created to pass as an argument, and the concrete type stored for that argument is the default type of the constant.
So the default type of the constant must be an int. The page goes on to talk about how the defaults get determined based on syntax, not necessarily the value of the const.
Big in fmt.Println(Big) has type integer which is more than max int value 9223372036854775807
you can find max int from this logic
const MaxUint = ^uint(0)
const MaxInt = int(MaxUint >> 1)
fmt.Println(MaxInt) // print 922337
2036854775807
To fix it, you need to cast it to float64 like this
fmt.Println(float64(Big))

How to represent empty byte in Go

Want to have an empty char/byte, which has zero size/length, in Go, such as byte("").
func main() {
var a byte = '' // not working
var a byte = 0 // not working
}
A more specific example is
func removeOuterParentheses(S string) string {
var stack []int
var res []byte
for i, b := range []byte(S) {
if b == '(' {
stack = append(stack, i)
} else {
if len(stack) == 1 {
res[stack[0]] = '' // set this byte to be empty
res[i] = '' // / set this byte to be empty
}
stack = stack[:len(stack)-1]
}
}
return string(res)
}
There is an equivalent question in Java
A byte is an alias to the uint8 type. Having an "empty byte" doesn't really make any sense, just as having an "empty number" doesn't make any sense (you can have the number 0, but what is an "empty" number?)
You can assign a value of zero (b := byte(0), or var b byte), which can be used to indicate that nothing is assigned yet ("zero value"). The byte value of 0 is is known as a "null byte". It normally never occurs in regular text, but often occurs in binary data (e.g. images, compressed files, etc.)
This is different from byte(""), which is a sequence of bytes. You can have a sequence of zero bytes. To give an analogy: I can have a wallet with no money in it, but I can't have a coin that is worth "empty".
If you really want to distinguish between "value of 0" and "never set" you can use either a pointer or a struct. An example with a pointer:
var b *byte
fmt.Println(b) // <nil>, since it's a pointer which has no address to point to.
one := byte(0)
b = &one // Set address to one.
fmt.Println(b, *b) // 0xc000014178 0 (first value will be different, as it's
// a memory address).
You'll need to be a little bit careful here, as *b will be a panic if you haven't assigned a value yet. Depending on how it's used it can either work quite well, or be very awkward to work with. An example where this is used in the standard library is the flag package.
Another possibility is to use a struct with separate fiels for the byte itself and a flag to record whether it's been set or not. In the database/sql library there are already the Null* types (e.g. NullInt64, which you can use as a starting point.
a single byte is a number. 0 would transform into a 8bit number. 00000000.
A byte slice/array can have a length of 0.
var a byte = 0
var b = [0]byte{}

Is there a nil value I can use for bytes in Go?

I'm implementing a tree in Go. My TreeNode struct looks like this:
type TreeNode struct {
payload byte
parent *TreeNode
children map[byte]*TreeNode
}
In my implementation, the root node of the tree is a special node that has no payload. Otherwise the payload is always a single lower-case letter from the English alphabet. So my tree initialization function looks like this:
func createEmptyTree(fileName string) *TreeNode{
return &TreeNode{
nil, // Line #180
nil,
false,
map[byte]*TreeNode{},
}
}
When I compile it though, I get the following error: ./main.go:180:9: cannot use nil as type byte in field value
So it seems I cannot use nil for a byte variable. Is there something else I could use in this situation? I could easily use '0' or other non alphabetic character. But it seems hacky. What should I do?
byte is a numeric type, actually an alias for uint8.
That means it has default zero value of 0.
For idiomatic Go, write your function as:
package main
import (
"fmt"
)
type TreeNode struct {
payload byte
parent *TreeNode
children map[byte]*TreeNode
}
func createEmptyTree(fileName string) *TreeNode {
return &TreeNode{
children: map[byte]*TreeNode{},
}
}
func main() {
tree := createEmptyTree("fiename")
fmt.Println(tree)
}
Playground: https://play.golang.org/p/v6DJCnpN6Ys
Output:
&{0 <nil> map[]}
The payload value for an empty tree is integer zero (0), the zero-value for the integer type byte. Zero is not a single lower-case letter value from the English alphabet.
The Go Programming Language Specification
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.
Every type in golang has a zero value. In the case of byte that is the null byte.
It's entirely possible to just use the null byte as a magical zero payload at the root.

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