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 a Book struct with three fields: ID (an unsigned integer), Title (a string), and Author (a string).
var Books []Book

  • var Books []Book: Declares a global variable Books which is a slice of Book structs.
func init() {
    Books = []Book {
        Book{
            ID: 1,
            Title: "halibote测试",
            Author: "mam",
        },
        Book{
            ID: 2,
            Title: "jifeigoutiao",
            Author: "an",
        },
    }
}

  • func init(): The init function is a special function in Go that is executed before the main function. It initializes the Books slice with two Book 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 a bookId as a string and returns a Book and an error.
  • defaultResult := Book{}: Creates a default empty Book instance.
  • for _, value := range Books: Iterates over the Books slice.
    • if strconv.FormatUint(value.ID, 10) == bookId: Converts the ID of each book to a string and compares it with bookId.
    • return value, nil: If a match is found, returns the matching Book and nil error.
  • return defaultResult, errors.New("not found " + bookId): If no match is found, returns the default Book 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"): Calls FindABook 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.