SoFunction
Updated on 2025-03-05

Go cast type(a) and data differences caused by range

1. Introduction

Type conversion points in golangForce type conversionandType AssertionNormal variable types int, float, string can be usedtype(a)This form is used to cast type conversion

2. Type conversion of numbers int and float

1. Integer type int

func TestInt(t *) {
    var i int = -1
    var i8 int8 = int8(i)
    var i16 int16 = int16(i)
    var i32 int32 = int32(i)
    var i64 int64 = int64(i)
    (i, i8, i16, i32, i64) //-1 -1 -1 -1 -1
    var n int = 1111111
    var n8 int8 = int8(n)
    var n16 int16 = int16(n)
    var n32 int32 = int32(n)
    var n64 int64 = int64(n)
    (n, n8, n16, n32, n64) //1111111 71 -3001 1111111 1111111
}

We found that when converting n to int8 and int16, an error occurred. Why is this happening?

In the case that the int type is the default 64 bits on the mac.

int8 represents an integer value between -128 and 127 (8 bits)

int16 represents the integer value between -32768 and 32767 (16 bits)

The ranges they can store are different, and if they exceed a certain type of range, they will make an error.

2. Positive integer type uint

func TestUint(t *) {
    var i uint = 1
    var i8 uint8 = uint8(i)
    var i16 uint16 = uint16(i)
    var i32 uint32 = uint32(i)
    var i64 uint64 = uint64(i)
    (i, i8, i16, i32, i64) //1 1 1 1 1
    var u uint = 1111111
    var u8 uint8 = uint8(u)
    var u16 uint16 = uint16(u)
    var u32 uint32 = uint32(u)
    var u64 uint64 = uint64(u)
    (u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111
}

Data conversion within the type range is correct, and conversion outside the range is wrong.

3. Cases between int and uint

func TestInt2(t *) {
    var i int = -1
    var i8 uint8 = uint8(i)
    var i16 uint16 = uint16(i)
    var i32 uint32 = uint32(i)
    var i64 uint64 = uint64(i)
    (i, i8, i16, i32, i64) //-1 255 65535 4294967295 18446744073709551615
    var n int = 1
    var n8 uint8 = uint8(n)
    var n16 uint16 = uint16(n)
    var n32 uint32 = uint32(n)
    var n64 uint64 = uint64(n)
    (n, n8, n16, n32, n64) //1 1 1 1 1
    var u int = 1111111
    var u8 uint8 = uint8(u)
    var u16 uint16 = uint16(u)
    var u32 uint32 = uint32(u)
    var u64 uint64 = uint64(u)
    (u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111
}

We found that when each type has different ranges, there will still be a big mistake if the conversion is not careful.

4. Cases between float32 and float64

func TestFloat(t *) {
    var f32 float32 = 333.333
    var f64 float64 = float64(f32)
    (f32, f64) //333.333 333.3330078125

    //Everything is within its own scope    var fl64 float64 = 333.333
    var fl32 float32 = float32(fl64)
    (fl64, fl32) //333.333 333.333

    //Large type range exceeds small type range    var flo64 float64 = 33333333333333333.333
    var flo32 float32 = float32(flo64)
    (flo64, flo32) //333.333 333.333
}

First, we judge the difference between float32 and float64, because the memory size is different, resulting in different accuracy and range.

  • float32 and float64 are converted to each other because the accuracy is different, resulting in data differences
  • float32 and float64 are converted to each other because the range is different, resulting in data differences

5. Float and int convert each other

func TestFloatInt(t *) {
    var i int = 333
    var f32 float32 = float32(i)
    var f64 float64 = float64(i)
    (i, f32, f64) //333 333 333
    var f float32 = 333.3
    var n int = int(f)
    var n8 int8 = int8(f)
    var n16 int16 = int16(f)
    var n32 int32 = int32(f)
    var n64 int64 = int64(f)
    (f, n, n8, n16, n32, n64) //333.3 333 77 333 333 333
}

Because it is a Mac system, I am int here as a signed 64-bit integer data type.

type Number of bits Valid numbers Numerical range
int64 64 -2^63 ( -9,223,372,036,854,775,808) 2^63-1(+9,223,372,036,854,775,807 )
float32 32 6-7 -3.410(-38)~3.410(38)
float64 64 15-16 -1.710(-308)~1.710(308)

Basically, when int is converted to float type, there is no problem as long as it is within range.
When converting float to int, you need to consider that the decimal point will be automatically discarded and the range issue.

3. Conversion of any pointer type and specific pointer type

Note that any pointer type can only be converted into a specific type of pointer type
If converted to int type pointer type *int
The syntax for forced quasi-change is type(a), so it is here (*int)(a), not int(a)!

1. Convert pointer to int pointer type

func TestIntPointer(t *) {
    //Scenarios where the conversion can be correct within the scope    var i int = 100
    pi := (&i)
    //Convert to int related types    var n *int = (*int)(pi)
    var n8 *int8 = (*int8)(pi)
    var n16 *int16 = (*int16)(pi)
    var n32 *int32 = (*int32)(pi)
    var n64 *int64 = (*int64)(pi)
    (*n, *n8, *n16, *n32, *n64)//100 100 100 100 100
    //--------------------------
    //Scope exceeds the scope    var i2 int = 10000
    pi2 := (&i2)
    //Convert to int related types    var nn *int = (*int)(pi2)
    var nn8 *int8 = (*int8)(pi2)
    var nn16 *int16 = (*int16)(pi2)
    var nn32 *int32 = (*int32)(pi2)
    var nn64 *int64 = (*int64)(pi2)
    (*nn, *nn8, *nn16, *nn32, *nn64)//10000 16 10000 10000 10000
}

Although this is a pointer, you still need to pay attention to the scope of the specific type.

Otherwise, it will still be wrong to exceed the maximum or minimum value of the type.

2. Convert pointer to struct pointer type

Or type(a), where the a variable is (&a)
type is (*Struct)

The complete expression is (*Struct)((&a))

func TestStruct(t *) {
    //There is a struct structure S, with two int types: width and height    type S struct {
        wight  int
        height int
    }
    s := S{
        wight:  5,
        height: 6,
    }
    p := (&s) //{5 6}
    (s)
    //Test is converted to T, and there are two int types: w and h in T.    type T struct {
        w int
        h int
    }
    st := (*T)(p)
    (*st) //{5 6}
}

It was found that although the two structures S and T were different, they were converted to the correct value. Why?

Because the memory holdings that the pointer focuses on, whether it is wight in S or w in T, are actually int types and occupy the same memory

So it can be parsed correctly

If we change the type of T to int8 at this time, we will find an error

func TestStruct(t *) {
    //There is a struct structure S, with two int types: width and height    type S struct {
        wight  int
        height int
    }
    s := S{
        wight:  5,
        height: 6,
    }
    p := (&s) //{5 6}
    (s)
    //Test is converted to T, there are two int8 types w and h in T.    type T struct {
        w int8
        h int8
    }
    st := (*T)(p)
    (*st) //{5 0}
}

The first 5 value obtained is that it can be obtained because it is offset 0 in the pointer, and it is just within the range. If = 10000
Then the first one will also be wrong, as follows

func TestStruct(t *) {
    //There is a struct structure S, with two int types: width and height    type S struct {
        wight  int
        height int
    }
    s := S{
        wight:  10000,
        height: 6,
    }
    p := (&s) //{10000 6}
    (s)
    //Test is converted to T, there are two int8 types w and h in T.    type T struct {
        w int8
        h int8
    }
    st := (*T)(p)
    (*st) //{16 39}
}

So we can conclude that if it is a pointer type, as long as the pointers inside are the same, they can be cast to the correct value.

The above is the detailed content of go cast type(a) and data differences caused by range. For more information about go cast type data differences, please pay attention to my other related articles!