Golang - Type decimal.Decimal convert - go

Trying to convert type decimal.Decimal to string
func main() {
a := strconv.Itoa(Price) // Price of type decimal.Decimal
fmt.Printf("%q\n", a)
}
Problem: cannot use (variable of type decimal.Decimal) as int value in argument to strconv.Itoa (compile)go-staticcheck
Example code that works will be apreciated

Price is decimal.Decimal not int. strconv.Itoa accepts int.
From docs https://pkg.go.dev/github.com/shopspring/decimal#Decimal.String
use .String().

Related

How to get the int value of an enum in golang? [duplicate]

Suppose I have a type alias like this:
type myint int;
Now I have a myint type called foo. Is there any way to convert foo from a myint to an int?
Use a conversion to convert a myint to an int:
package main
import "fmt"
type myint int
func main() {
foo := myint(1) // foo has type myint
i := int(foo) // use type conversion to convert myint to int
fmt.Println(i)
}
The type myint is a not an alias for int. It's a different type. For example, the expression myint(0) + int(1) does not compile because the operands are different types. There are two built-in type aliases in Go, rune and byte. Applications cannot define their own aliases.

Printing value of a *big.Int field in a Go struct

I have a big.Int I need to store inside of a struct, but when I try to do so it overflows. Code example below
type NumberStore struct {
mainnumber *big.Int
}
var ledger NumberStore
// In decimal this is 33753000000000000000
var largehex string = "1D46ABEAB3FC28000"
myNumber := new(big.Int)
myNumber.SetString(largehex, 16)
ledger.mainnumber = myNumber
fmt.Println(ledger)// Prints 0xc0000a64c0, but I need it to be 33753000000000000000
Since mainnumber is a pointer field in your NumberStore struct, printing out the struct by default will just print out the value of the pointer, not the value it points to.
As the comment says, if you make your field exported then fmt.Println will show the underlying value; but if you don't need it exported, then fmt.Println(ledger.mainnumber) should print the number you expect. Here's your full code with one line added at the end:
package main
import (
"fmt"
"math/big"
)
type NumberStore struct {
mainnumber *big.Int
}
func main() {
var ledger NumberStore
// In decimal this is 33753000000000000000
var largehex string = "1D46ABEAB3FC28000"
myNumber := new(big.Int)
myNumber.SetString(largehex, 16)
ledger.mainnumber = myNumber
fmt.Println(ledger)
fmt.Println(ledger.mainnumber)
}
Run on the Playground, it prints:
{0xc000092000}
33753000000000000000
By printing like this fmt.Println(ledger), you're relying on the default formatting of the value ledger. For each field in the struct, it will only print the default representation of that value, unless it can access the appropriate custom formatting code for that type. For mainnumber of type *big.Int, that is "pointer to big.Int", it's simply printing the pointer address.
In order to give fmt access to the custom string formatting code for a *big.Int value, you either need to pass it directly: fmt.Println(ledger.mainnumber), or change mainnumber to an exported field, like this:
type NumberStore struct {
Mainnumber *big.Int
}
The fmt package cannot automatically find the value's formatting code (the .String() string method) if it is an unexported struct field.

How to convert map[string][]byte to map[string]interface{}

I have a function that excepts parameter of type map[string]interface{} but I have variable of type map[string][]byte. my question is how can I convert map[string][]byte to map[string]interface{} in Go.
This is a common miss-expectation from go. In this case each element of the map needs to be converted to interface.
So here's a workaround with sample code:
func foo(arg map[string]interface{}){
fmt.Println(arg)
}
// msaToMsi convert map string array of byte to map string interface
func msaToMsi(msa map[string][]byte) map[string]interface{}{
msi := make(map[string]interface{}, len(msa))
for k, v := range msa {
msi[k] = v
}
return msi
}
func main() {
msa := map[string][]byte{"a": []byte("xyz")}
foo(msaToMsi(msa))
}
The solution would be similar for the following map or array conversion as well:
map[string]string to map[string]interface{}
[]string to [] interface {}
Etc..
Ok so to answer your question an interface in GO can be used where you are passing or receiving a object/struct of where you are not sure of its type.
For example:
type Human struct {
Name string
Age int
School string
DOB time.Time
}
type Animal struct {
Name string
HasTail bool
IsMamal bool
DOB time.Time
}
func DisplayData(dataType interface{}, data byte)
This Display Data function can Display any type of data, it takes data and a struct both of which the function doesn't know until we pass them in... The data could be a Human or an Animal, both having different values which can be mapped depending on which interface we pass to the function...
This means we can reuse the code to display any data as long as we tell the function the data type we want to map the data to and display (i.e. Animal or Human...)
In your case the solution would be to define the data type, the structure of the data in the byte as a struct and where you make the map instead of map[string][]byte
try changing to
map[string]YourDefinedStructure
and pass that to the function that accepts map[string]interface{}.
Hopefully this helps, the question although you supply data types is rather vague as a use case and nature of the function that accepts map[string]interface{} can affect the approach taken.
You don't really have to convert while passing your map[string][]byte to the function.
The conversion needs to happen at the point where you want to use the value from the map.

Converting time from DB to custom time fails

I need to read dates from a db, convert it to a certain timestamp and convert it to JSON.
I have the following code:
package usages
import (
"fmt"
"time"
)
type SpecialOffer struct {
PublishedDate jsonTime `gorm:"column:publishing_date" json:"published_date"`
ExpirationDate jsonTime `gorm:"column:expiration_date" json:"expiration_date"`
}
type jsonTime struct {
time.Time
}
func (tt jsonTime) MarshalJSON() ([]byte, error) {
jsonTime := fmt.Sprintf("\"%s\"", tt.Format("20060102"))
return []byte(jsonTime), nil
}
When I run it like this I get the following error:
sql: Scan error on column index 8, name "publishing_date": unsupported Scan, storing driver.Value type time.Time into type *usages.trvTime
And the data is wrong:
{"published_date":"00010101","expiration_date":"00010101"}
If I change the SpecialOffer struct to use time.Time, it return correct, but obviously the format is wrong:
{"published_date":"2020-03-12T00:00:00Z","expiration_date":"2020-06-12T00:00:00Z"}
What am I doing wrong?
You should implement the sql.Scanner and driver.Valuer interfaces.
Something like this:
func (j *jsonTime) Scan(src interface{}) error {
if t, ok := src.(time.Time); ok {
j.Time = t
}
return nil
}
func (j jsonTime) Value() (driver.Value, error) {
return j.Time, nil
}
This is necessary because the database/sql package which is used by gorm and some other go ORMs, if not all of them, provides out-of-the-box support for only a handful of types.
Most of the supported types are the language's basic builtin types like string, int, bool, etc. by extension it also supports any custom user defined type whose underlying type is one of the aforementioned basic types, then there's supports for the []byte type and the related sql.RawBytes type, and lastly the time.Time type is also supported ootb.
Any other type that you may want to write to or read from the database will need to implement the two interfaces above. The sql.Scanner's Scan method is invoked automatically after a column's value is decoded into one of the supported types (that's why you need to type assert against time.Time rather than against, say []byte). The driver.Valuer's Value method is invoked automatically before the driver encodes it into a format that's valid for the target column (that's why you can return time.Time directly rather than having the do the encoding yourself).
And keep in mind that
type jsonTime struct {
time.Time
}
or even
type jsonTime time.Time
declares a new type that is not equal to time.Time and that is why it's not picked up by the database/sql package.

Go Redefined type formating and methods

Here is a basic go program
package main
import (
"fmt"
"time"
)
type myTime time.Time
func main() {
my := myTime(time.Now())
fmt.Println(my)
normal := time.Now()
fmt.Println(normal)
}
And the corresponding output
{63547112172 291468455 0x545980}
2014-09-23 23:36:12.292132305 +0000 UTC
I would like to know why myTime prints diffrently than time.Time. They basically are supposed to be from the same type... Also, if I try to access any method of time.Time, let's say, Day, it's available for "normal" but not for "my".
Thanks!
Your new type does not inherit methods from time.Time. To quote the spec:
The declared type does not inherit any methods bound to the existing type
Since there is no String method, it won't print a meaningful value. You need to implement that yourself.
Your other option is to embed time.Time in your own type. That way you can include the functionality of time.Time but also add your own functionality.
Playground link: http://play.golang.org/p/PY6LIBoP6H
type myTime struct {
time.Time
}
func (t myTime) String() string {
return "<Custom format here>"
}
func main() {
my := myTime{time.Now()}
fmt.Println(my)
normal := time.Now()
fmt.Println(normal)
}
fmt.Println uses the String() method (or rather the fmt.Stringer interface) when formatting a type as a string, if it is available. When you create a new type using an underlying type (in your case time.Time):
type myTime time.Time
You will not inherit the methodset of the underlying type. Therefore, myTime has no String() method, so fmt will use the default format for a struct.

Resources