others-how to solve 'cannot use value.ID (type uint) as type uint64 in argument to strconv.FormatUint' when running golang program ?
Problem
When we run a golang ( or go) progam as follows:
go run main.go
sometimes , we get this error:
models/book.go:37:30: cannot use value.ID (type uint) as type uint64 in argument to strconv.FormatUint
Why do this error happen? The golang program is correct, I promise!!!
Environment
- go version go 1.14+
The code
The main code of the program is:
package main
import (
"errors"
"fmt"
"strconv"
)
type Book struct {
ID uint
Title string
Author string
}
var Books []Book
func init() {
Books = []Book {
Book{
ID: 1,
Title: "halibote测试",
Author: "mam",
},
Book{
ID: 2,
Title: "jifeigoutiao",
Author: "an",
},
}
}
func FindABook(bookId string)(Book,error) {
defaultResult := Book{}
for _,value:=range Books {
if strconv.FormatUint(value.ID,10)==bookId {
return value,nil
}
}
return defaultResult,errors.New("not found "+bookId)
}
func main() {
book, err := FindABook("3")
if err == nil {
fmt.Printf(" got book %v\n", book)
}else {
fmt.Printf("%v\n",err)
}
}
The above Go
code defines a simple program to manage a collection of books and search for a book by its ID. Let’s break it down step by step.
package main
import (
"errors"
"fmt"
"strconv"
)
package main
: This defines the package as the main package, meaning this is an executable program.import
: The import statements bring in necessary packages:errors
: For creating error values.fmt
: For formatted I/O operations like printing to the console.strconv
: For string conversions, particularly between strings and numeric types.
type Book struct {
ID uint
Title string
Author string
}
type Book struct
: Defines aBook
struct with three fields:ID
(an unsigned integer),Title
(a string), andAuthor
(a string).
var Books []Book
var Books []Book
: Declares a global variableBooks
which is a slice ofBook
structs.
func init() {
Books = []Book {
Book{
ID: 1,
Title: "halibote测试",
Author: "mam",
},
Book{
ID: 2,
Title: "jifeigoutiao",
Author: "an",
},
}
}
func init()
: Theinit
function is a special function in Go that is executed before the main function. It initializes theBooks
slice with twoBook
instances.
func FindABook(bookId string)(Book,error) {
defaultResult := Book{}
for _,value:=range Books {
if strconv.FormatUint(value.ID,10)==bookId {
return value,nil
}
}
return defaultResult,errors.New("not found "+bookId)
}
func FindABook(bookId string) (Book, error)
: This function takes abookId
as a string and returns aBook
and an error.defaultResult := Book{}
: Creates a default emptyBook
instance.for _, value := range Books
: Iterates over theBooks
slice.if strconv.FormatUint(value.ID, 10) == bookId
: Converts theID
of each book to a string and compares it withbookId
.return value, nil
: If a match is found, returns the matchingBook
andnil
error.
return defaultResult, errors.New("not found " + bookId)
: If no match is found, returns the defaultBook
and an error indicating the book was not found.
func main() {
book, err := FindABook("3")
if err == nil {
fmt.Printf(" got book %v\n", book)
} else {
fmt.Printf("%v\n", err)
}
}
func main()
: The entry point of the program.book, err := FindABook("3")
: CallsFindABook
with the ID “3”.if err == nil
: Checks if no error was returned.fmt.Printf(" got book %v\n", book)
: If no error, prints the found book.fmt.Printf("%v\n", err)
: If there was an error, prints the error message.
This program initializes a list of books and provides a function to search for a book by its ID. If a book with the given ID is found, it prints the book; otherwise, it prints an error message indicating the book was not found
Reason of the problem
Our Book’s ID’s type is uint, it can not be converted to uint64, which is required by strconv.FormatUint.
This is the definition of the strconv.FormatUint:
func FormatUint(i uint64, base int) string
FormatUint returns the string representation of i in the given base, for 2 <= base <= 36. The result uses the lower-case letters ‘a’ to ‘z’ for digit values >= 10.
Solution #1
We should change the type of Book.ID before the string conversion:
func FindABook(bookId string)(Book,error) {
defaultResult := Book{}
for _,value:=range Books {
if strconv.FormatUint(uint64(value.ID),10)==bookId {
return value,nil
}
}
return defaultResult,errors.New("not found "+bookId)
}
The key point is :
if strconv.FormatUint(uint64(value.ID),10)==bookId {
We use uint64() to convert uint to uint64.
Solution #2
We can also change our Book’s definition like this:
type Book struct {
ID uint64
Title string
Author string
}
Then we convert it to string like this:
if strconv.FormatUint(value.ID,10)==bookId {
Solution #3
We can still use the uint type, and try to convert it to string using fmt.Sprint as follows:
type Book struct {
ID uint
Title string
Author string
}
...
func FindABook(bookId string)(Book,error) {
defaultResult := Book{}
for _,value:=range Books {
if idstring := fmt.Sprint(value.ID); idstring==bookId {
return value,nil
}
}
return defaultResult,errors.New("not found "+bookId)
}
Here we use the fmt.Sprint function to convert the uint type to string, let’s check the definition of fmt.Sprint:
In Go language, fmt package implements formatted I/O with functions analogous to C’s printf() and scanf() function. The fmt.Sprint() function in Go language formats using the default formats for its operands and returns the resulting string.
Run the app again, No error messages ,It works!
By the way
The basic types of integer in golang:
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.