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)
    }
}

Reason

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.