GO 从 0 到 1 系列:2 go 数据类型

2 go 数据类型

2.1 基础数据类型

基础数据类型

类型 长度(字节,byte) 默认值 说明
bool 1 false
byte 1 0 uint8,取值范围[0,255], 字节类型,取值范围同uint8,赋值得时候是''
rune 4 0 Unicode 码点,取值范围同uint32,赋值得时候是''
int, uint 4 或 8 0 32 或 64 位,取决于操作系统,uint 不能表示负数最大值比 int * 2
int8, uint8 1 0 -128 ~ 127, 0 ~ 255
int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32, uint32 4 0 -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint64 8 0
float32 4 0.0
float64 8 0.0
complex64 8
complex128 16
uintptr 4 或 8 以存储指针的 uint32 或 uint64 整数

2.1.1 演示基础数据类型范例

2.1.1.1 基础数据类型默认值

1.取默认类型以及 float 精度问题范例

package main

import "fmt"

func default_value() {
    // var 定义基础数据类型但是并不赋值
    var a int
    var b byte
    var f float32 = 2.4578
    var t bool
    var s string
    var r rune
    var arr []int

    // 通过 printf 输出每个变量的默认值
    fmt.Printf("default value of int %d\n", a)
    fmt.Printf("default value of byte %d\n", b)

    // %.2f 小数点保留两位并四舍五入,%.3e 小数点保留3位科学计数,%g 保留原始精度并输出
    fmt.Printf("default value of float32 %.2f,%.3e,%g\n", f, f, f)

    // %t 表示输出 bool 变量
    fmt.Printf("default value of bool %t\n", t)
    fmt.Printf("default value of string [%s]\n", s)
    fmt.Printf("default value of rune [%c]\n", r)
    fmt.Printf("default value of slice %v\n", arr)
}

func main() {
    // 调用函数
    default_value()
}

输出结果

[11:05:14 root@go day2]#go run main.go 
default value of int 0                              # 默认值 0
default value of byte 0                             # 默认值 0
default value of float32 2.46,2.458e+00,2.4578      # 可以看到2.46 四舍五入,科学计数,和保留原始精度
default value of bool false                         # 默认值 false
default value of string []                          # 默认值 空
default value of rune   []                          # 默认值 Unicode Code
default value of slice []                           # 默认值 nil

2.1.1.2 复数类型演示

1.复数类型演示

通过下面两个函数获取 complex 实数和虚数

real() 函数:// real 内置函数返回复数 complex 的实数部分。返回值将是与 complex 类型对应的浮点类型。
imag() 函数:// imag 内置函数返回复数 complex 的虚数部分。返回值将是与 complex 类型对应的浮点类型。

在 go 中复数分为实部和虚部

 package main

import (
    "fmt"
)

func default_complex() {
    var m complex64
    m = complex(2, 6)

    // real函数获取复数的实部,imag 函数获取复数虚部
    fmt.Printf("%T %T\n", real(m), imag(m))
}

func main() {

    default_complex()
}

输出:看到是类型是 float32

[11:24:44 root@go day2]#go run main.go 
float32 float32

如果说我们将复数类型换为 128 看看会怎么样

输出:

# 输出两个 float64 
[11:24:53 root@go day2]#go run main.go 
float64 float64

总结:

complex 所谓的 64 和 128 位,都是通过实部和虚部两数相加的到,所以能分析出为什么类型分别是 float32 位和 float64 位,而且由此得出复数的实部和虚部其实就是浮点数

如:float64 + float64 = complex128float32 + float32 = complex64

2.输出复数默认值

这里我在代码中通过 %f 取出实部和虚部的默认值,并且通过 %T 取出 m 变量的类型

package main

import (
    "fmt"
)

func default_complex() {
    var m complex128
    m = complex(2, 6)

    // real函数获取复数的实部,imag 函数获取复数虚部
    fmt.Printf("%T %T\n", real(m), imag(m))

    // 取默认值
    fmt.Printf("real %f , imag %f\n", real(m), imag(m))

    // 取变量类型
    fmt.Printf("m type = %T\n", m)
}

func main() {
    default_complex()
}

输出:

[11:39:11 root@go day2]#go run main.go 
float64 float64                            # complex128 实部和虚部的值类型
real 2.000000 , imag 6.000000              # 实部虚部默认值
m type = complex128                        # m 变量类型为 complex128

2.1.1.3 bool 类型演示并实现短申明

注意:

如果使用短声明的话只能够在作用域内使用,并不能在全局使用

package main

import (
    "fmt"
)

func bools() {
    // 短声明,声明并赋值
    o := true

    // 对 o 变量赋值
    o = false

    // 并且还能通过 var 定义的时候赋值
    var b = true

    fmt.Printf("%T,%t\n", o, o)
    fmt.Printf("%T,%t\n", b, b)
}

func main() {
    bools()
}

输出

[14:36:56 root@go day2]#go run main.go 
bool,false
bool,true

2.1.1.4 指针类型

其实我们可以将指针理解为权限功能会比较大,可以通过较少的代码来实现复杂的功能

指针类型可有下面三种方法进行对某个变量的地址取值

unsafe.Pointer  // 是特别定义的一种指针类型(译注:类似C语言中的void*类型的指针),它可以包含任意类型变量的地址。
uintptr         // uintptr是golang的内置类型,是能存储指针的整型,在64位平台上底层的数据类型是,
*type           // 对变量类型直接通过 * 取址

unsafe.Pointer

大多数指针类型会写成*T,表示是“一个指向T类型变量的指针”。unsafe.Pointer是特别定义的一种指针类型(译注:类似C语言中的void*类型的指针),它可以包含任意类型变量的地址。当然,我们不可以直接通过*p来获取unsafe.Pointer指针指向的真实变量的值,因为我们并不知道变量的具体类型。和普通指针一样,unsafe.Pointer指针也是可以比较的,并且支持和nil常量比较判断是否为空指针。

一个普通的*T类型指针可以被转化为unsafe.Pointer类型指针,并且一个 unsafe.Pointer 类型指针也可以被转回普通的指针,被转回普通的指针类型并不需要和原始的*T类型相同。

package main

import (
    "fmt"
    "unsafe"
)

func demo() {
    var a int

    // 通过下面上种方式来对 a 变量进行取指针地址
    var pointer unsafe.Pointer = unsafe.Pointer(&a)
    var p uintptr = uintptr(pointer)
    var ptr *int = &a

    // 格式化输出 %p 输出指针类型
    fmt.Printf("pointer = %p,p = %x , ptr = %p\n", pointer, p, ptr)
}

func main() {
    demo()
}

输出发现这三种方式取出来的地址值都是一样的

[15:11:39 root@go day2]#go run main.go 
pointer = 0xc0000a8000,p = c0000a8000 , ptr = 0xc0000a8000

2.1.1.5 byte 类型

package main

import "fmt"

func main() {
    var b byte = 100 // byte 等价于 uint8, rune 等价于 int32
    fmt.Printf("%T\n", b)

    // 格式 %b 输出二进制
    fmt.Printf("%b\n", b)
}

输出可以看到是一个 uint8,因为我们都知道 byte 的底层其实就是一个 uint8

[15:12:45 root@go day2]#go run main.go 
uint8
1100100

2.1.1.6 rune 类型

rune 是一个字符

package main

import "fmt"

func main() {
    var r rune = '😂'
    // %d 取出 r 的 unicode 码
    // %c 输出为字符类型
    fmt.Printf("%d %c\n", r, r)
}

输出

[15:18:09 root@go day2]#go run main.go 
128514 😂

# 128514 unicode 码

2.1.1.7 error 类型

因为在 go 语言中需要抛出错误,所以在 go 中有一个特别的类型也就是 error,并且 error 是一个结构体

package main

import (
    "errors"
    "fmt"
)

func main() {
    // 声明
    var e error

    // 赋值
    // 可以看到 error是其实一个函数并返回一个 error func errors.New(text string) error
    e = errors.New("test error")

    // 当我们在遇见比较复杂的数据类型的时候可以通过 %v 输出
    // %#v 会将去该变量的所有内容输出
    fmt.Printf("%T\n%v\n%#v\n", e, e, e)
}

输出

[15:29:31 root@go day2]#go run main.go 
*errors.errorString                     # %T 类型是一个结构体
test error                              # %v 获取变量的值
&errors.errorString{s:"test error"}     # %#v 将该变量所有内容输出

2.1.1.8 struct 类型

struct 其实就是结构体类型

package main

import "fmt"

func main() {
    // 定义 user 结构体
    type user struct {
        Name string
        Age  int
    }

    // 赋值实例给 u
    u := user{Name: "张三", Age: 12}

    // %v 输出内容
    fmt.Printf("%v\n", u)

    // %+v 输出结构体属性和值
    fmt.Printf("%+v\n", u)

    // %#v 输出结构体名称以及属性和值
    fmt.Printf("%#v\n", u)
}

输出

[15:30:40 root@go day2]#go run main.go 
{张三 12}                             # %v 输出内容
{Name:张三 Age:12}                    # %+v 输出结构体属性和值
main.user{Name:"张三", Age:12}        # %#v 输出结构体名称以及属性和值

2.2 复合数据类型

复合数据类型

类型 默认值 说明
array 值类型
struct 值类型
string “” UTF-8 字符串
slice nil 引用类型,在不赋值的情况下默认值 nil
map nil 引用类型,在不赋值的情况下默认值 nil
channel nil 引用类型,在不赋值的情况下默认值 nil
interface nil 接口,在不赋值的情况下默认值 nil
function nil 函数,在不赋值的情况下默认值 nil

2.2.1 自定义类型

// 类型别名,go 源码中就是这么写的
type byte = uint8
type rune = int32

// 自定义类型
type signal uint8                       // signal 就变为了 uint8 类型,下面依次类推
type ms map[string]string
type add func(a, b int) int             // 定义 add 为来一个自定义函数类型,接收两个 int 返回一个 int
type user struct {name string;age int}

那么自定义类型和类型别名之间有什么区别呢?除了形式上和使用的时候有没有本质的区别呢?

其实两者之间还是有区别:

  • 自定义类型:如果是自定义类型的话我们就可以将其理解为一个结构体,结构体的话就会包括他的元素,以及方法呀
  • 类型别名:就不能通过方法实现,不能拥有方法

2.2.1.1 自定义类型常规范例

通过代码演示:

package main

import "fmt"

// 常规类型:
// 将 user 定义为 struct 类型,并且有 nage 和 age 两个元素
type User struct {
    Name string
    Age  int
}

/*
    常规方式:
    定义 hello 方法
    方法的作用其实和函数类型,只是写法上不同如果想实现该方法必须的先实现该实例
    u *User 其实就相当于对 u 变量进行赋值,从而生成该结构体的实例
*/
func (u *User) hello() {
    u.Name = "zgy"
    fmt.Printf("my name is %s\n", u.Name)
}

func main() {
    // 在 main 函数中赋值 u 类型为 user{},并拥有 user{} 的方法
    u := User{}

    // 调用 hello 方法
    u.hello()
}

输出

[16:29:30 root@go day2]#go run main.go 
my name is zgy

2.2.1.2 自定义类型非常规范例

通过代码演示:

package main

import "fmt"

// 非常规方法:自定义类型
type map1 map[string]int

/*
    非常规方法:
    如下对于 map 类型而言想要查找一个元素或者读取一个元素是没有其他方法的
    但是这里我们自定义了一个 map 类型,并且通过给它加一个方法实现读取该 map 中的元素值
*/

// 定义 say 方法
func (m map1) Say() {
    // 通过 make 给 map 类型分配内存
    m = make(map1)
    m["hello"] = 1
    fmt.Printf("Say() %d\n", m["hello"])
}
func main() {
    // 实例
    var ms map1
    ms.Say()
    fmt.Printf("type = %T\nvalue = %v\n", ms, ms)
}

输出:

[16:39:00 root@go day2]#go run main.go 
Say() 1                 # 调用 say 方法
type = main.map1        # 类型为自定义类型
value = map[]           # 默认值为 map 

2.2.2 字符串类型

Go 语言内置了字符串类型,使用 string 表示

字面量:

  • 可解析字符串:通过双引号"来创建,不能包含多行,支持特殊字符转义序列
  • 原生字符串:通过反引号 “ ` 来创建,可包含多行,不支持特殊字符转义序列

特殊字符:

  • \:反斜线转义字符
  • \’:单引号
  • \”:双引号
  • \a:响铃
  • \b:退格
  • \f:换页
  • \n:换行
  • \r:回车
  • \t:制表符
  • \v:垂直制表符
  • \ooo:3 个 8 位数字给定的八进制码点的 Unicode 字符(不能超过\377)
  • \uhhhh:4 个 16 位数字给定的十六进制码点的 Unicode 字符
  • \Uhhhhhhhh:8 个 32 位数字给定的十六进制码点的 Unicode 字符
  • \xhh:2 个 8 位数字给定的十六进制码点的 Unicode 字符
//字符串里可以包含任意 Unicode 字条
s1 := "My name is 张桂元☻"                         

// \ 包含转义字符
s2 := "He say:\"I'm fine.\" \n\\Thank\tyou.\\"        

//反引号里的转义字符无效。反引号里的原封不动地输出,包括空白符和换行符
s3 := `here is first line. 

there is third line.
` 

string 原理

string :中每个元素叫“字符”,字符有两种:
    byte   :1 个字节, 代表 ASCII 码的一个字符
    rune   :4 个字节,代表一个 UTF-8 字符,一个汉字可用一个 rune 表示

string :底层是 byte 数组, string 的长度就是该 byte 数组的长度, UTF-8 编码下一个汉字占 3 个 byte ,即一个汉字占 3 个长度,比如对一个汉字进行 for range 遍历,直接就会将这个汉字进行返回,而不会说返回 3 个字节

string :可以转换为 []byte 或 []rune 类型

string :是常量,不能修改其中的字符

获取 string 的 index:因为我们都知道 string 底层其实就是一个 byte 数组,从而可以直接通过下标来获取他的字符

2.2.1.1 字符串常用操作

方法 介绍
len(str) 求长度
strings.Split 分割
strings.Contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Index(),strings.LastIndex() 子串出现的位置,如果说没有找到就返回 -1

2.2.1.2 byte 演示

package main

import "fmt"

func main() {
    // 定义 string
    s := "dasf 3234 张桂元"

    // 将 s 字符串转为 byte 切片
    arr := []byte(s)

    // 遍历切片的每个元素,字符串的每一个元素都是一个 byte
    for _, v := range arr {
        fmt.Printf("%d ", v)
    }

    fmt.Println()

    // 字符串和切片长度必须一样
    fmt.Printf("切片长度 = %d , 字符串长度 = %d\n", len(arr), len(s))
}

输出

[17:28:56 root@go day2]#go run main.go 
100 97 115 102 32 51 50 51 52 32 229 188 160 230 161 130 229 133 131 
切片长度 = 19 , 字符串长度 = 19

如果说这里我将 张桂元 这三个汉字去掉

输出,可以看到长度变为 10 ,每个汉字占用 3 个字节

[17:30:17 root@go day2]#go run main.go 
100 97 115 102 32 51 50 51 52 32 
切片长度 = 10 , 字符串长度 = 10

而且每个汉字占用 3 个字节数

[17:30:25 root@go day2]#go run main.go 
229 188 160 
切片长度 = 3 , 字符串长度 = 3
2.2.1.2.1 byte 识别 UTF-8 范例
package main

import "fmt"

func main() {
    // 定义字符串
    s := "2 二"

    // 切片转义为 byte 类型
    arr := []byte(s)

    // 输出 50, 32, 228, 186, 140
    fmt.Println(arr)

    // 然后在将得到的元素定义为 byte 切片的值
    crr := []byte{50, 32, 228, 186, 140}

    // 强转义为 string 
    fmt.Println(string(crr))
}

[18:09:46 root@go day2]#go run main.go 
[50 32 228 186 140]
2 二

2.2.1.3 rune 演示

这里我将字符串转为 rune 的数组,而我们都知道 rune 底层是一个 uint32 取值范围为:[0,4294967295]

package main

import "fmt"

func main() {
    // 定义 string
    s := "张"

    // 转为 rune 切片
    arr := []rune(s)

    for _, v := range arr {
        fmt.Printf("遍历值:%d ", v)
    }

    fmt.Println()

    fmt.Printf("切片长度 = %d , 字符串长度 = %d\n", len(arr), len(s))
}

可以看到遍历的值其实就是一个 unicode 编码,而该切片的长度为 1

[17:35:08 root@go day2]#go run main.go 
遍历值:24352 
切片长度 = 1 , 字符串长度 = 3

2.2.1.4 反引号原生字符串演示

在字符串中通过 “ 反引号进行赋值的话是不能够实现转义的,下面就通过代码为大家演示一下

package main

import "fmt"

func main() {
    // "" 演示能够转义
    s1 := "hello \nworld 123"

    // `` 反引号不能识别转义,并且能够回车
    s2 := `hello \n 
    123
// world 顶头写才能实现换行第一个位置
world`
    fmt.Printf("s1 = %s\n\ns2 = %s\n", s1, s2)
}

通过输出可以看到在 “ 中的 \n 并不能实现转义

[17:51:46 root@go day2]#go run main.go 
s1 = hello 
world 123

s2 = hello \n 
        123
world                   # 所以说在原生的字符串中会将内容原封不动的输出

2.2.3 strings 包实现对字符串操作

go 的话没有提供相关的方法去对字符串进行操作,而是提供了 strings 包,然后再 strings 包中提供了很多函数,可以对字符串进行操作

2.2.3.1 字符串分割

源码:

func Split(s, sep string) []string { 
    return genSplit(s, sep, 0, -1) 
}

/*
    s 传入需要分割的字符串,sep 通过什么字符串进行分割,返回一个 string 切片
    将 sep 分割为所有由 sep 分隔的子字符串,并返回这些分隔符之间的子字符串片段。
    如果 s 不包含 sep 且 sep 不为空,则 Split 返回长度为 1 的切片,其唯一元素为 s。
    如果 sep 为空,则在每个 UTF-8 序列后拆分。如果 s 和 sep 都为空,则 Split 返回一个空切片。
    它相当于 SplitN 的计数为 -1。
*/
package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "hello ,how are you"

    // 通过 strings.Split 将 s 字符串通过 , 进行分割将返回的切片赋值给 arr 变量,
    arr := strings.Split(s, ",")

    // for-range 遍历 arr
    for _, v := range arr {
        fmt.Println(v)
    }
}

输出:

[18:16:27 root@go day2]#go run main.go 
hello 
how are you

2.2.3.2 是否包含某个字符串

源码:

func Contains(s, substr string) bool {
    return Index(s, substr) >= 0
}
// 第一个参数传入字符串,第二个参数传入是否包含该字符串
// 如果包含返回 true
// 如果不包含返回 false
package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "hello ,how are you"
    // 因为在 s 字符串中包含了 o return true
    fmt.Println(strings.Contains(s, "o"))

    // 在字符串中没有包含 22 return false
    fmt.Println(strings.Contains(s, "22"))
}
[18:21:44 root@go day2]#go run main.go 
true
false

2.2.3.3 以什么开头以什么结尾

源码:

// HasPrefix
func HasPrefix(s, prefix string) bool {
    // 如果传入的字符串长度大于或者等于匹配的字符串
    // 并且对前面切片进行取值用于判断
    return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}


// HasSuffix
func HasSuffix(s, suffix string) bool {
    // 如果传入的字符串长度大于或者等于匹配的字符串
    // 并且对后面切片进行取值用于判断
    return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}
package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "hello ,how are you"

    // HasPrefix 以什么开头
    fmt.Println(strings.HasPrefix(s, "h"))

    // HasSuffix 以什么结尾
    fmt.Println(strings.HasSuffix(s, "you"))
}

输出

[18:43:54 root@go day2]#go run main.go 
true
true

2.2.3.4 查询字符串第一次出现的位置

package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "hello ,how are you"
    // 查询 ho 出现的 index
    fmt.Println(strings.Index(s, "ho"))
}

输出:将第一个匹配的字符串 index 输出

[18:50:34 root@go day2]#go run main.go 
7

2.2.3.5 查询字符串最后一次出现的位置

package main

import (
    "fmt"
    "strings"
)

func main() {
    s := "hello ,how are you"

    // 输出 o 最后一次出现的位置
    fmt.Println(strings.LastIndex(s, "o"))
}

输出

[18:57:46 root@go day2]#go run main.go 
16

2.2.4 字符串拼接

需要将多个字符串拼接为一个很长的字符串,可以使用下面四种方法

方法1:
/*
    加号连接
    如果通过加号将两个字符串进行拼接底层会去重新声明一块新的内存空间,然后将两个需要拼接的字符串进行拷贝,如果说我们需要连接很多个字符串的话他就会拷贝很多次从而程序的性能将大打折扣
*/

方法2:
// Sprintf 将多个传入的字符串进行拼接并放会一个 string
func fmt.Sprintf(format string, a ...interface{}) string

方法3:
// 通过 strings.join 函数
func strings.Join(elems []string, sep string) string

方法4:
// 当有大量的 string 需要拼接时,用 strings.Builder 效率最高,因为字符串本质上是一个常量,而常量定义好了之后是不允许往后面进行内容追加的,而 strings.Builder 第一次申请内存空间的时候就会一次性申请相对比较打的一块内存空间,从而后续不在会进行多次 copy 动作

代码:

package main

import (
    "fmt"
    "strings"
)

func main() {
    s1 := "aaaa"
    s2 := "bbbb"
    s3 := "cccc"

    // 方式1 通过 +
    fmt.Println("+ :", s1+s2+s3)

    // 方式2 通过 Sprintf
    sp := fmt.Sprintf("Sprintf:%s%s%s", s1, s2, s3)
    fmt.Println(sp)

    // 方式3 通过 join 函数
    fmt.Println("join:", strings.Join([]string{s1, s2, s3}, ""))

    // 方式4 Builder
    sb := strings.Builder{}
    sb.WriteString(s1)
    sb.WriteString(s2)
    sb.WriteString(s3)
    fmt.Println("Builder:", sb.String())
}

输出

[19:13:40 root@go day2]#go run main.go 
+ : aaaabbbbcccc
Sprintf:aaaabbbbcccc
join: aaaabbbbcccc
Builder: aaaabbbbcccc

# 实际上第三种方式和第四种方式性能是最高的

2.3 强制类型转换

  • byte和int可以互相转换
  • float和int可以互相转换,小数位会丢失
  • bool和int不能相互转换
  • 不同长度的int或float之间可以相互转换
  • string可以转换为[]byte或[]rune类型,byte或rune可以转为string
  • 低精度向高精度转换没问题,高精度向低精度转换会丢失位数
  • 无符号向有符号转换,最高位是符号位
  • 不能对常量执行强制类型转换

强制类型转换,其实需要注意的就是两个类型之间的最大值,如下面代码

package main

import "fmt"

func main() {
    var i int = 9
    by := byte(i) // 装维 byte
    fmt.Println(by)

    i = int(by) // 转为 int
    fmt.Println(i)

    // 如果说这里我将 i 从新赋值为 256 并且再强制转换给 by
    i = 256
    by = byte(i)
    fmt.Println(by)
}

输出

[22:38:00 root@go day2]#go run main.go 
9
9
0                       # 可以看到在强制类型转换的时候如果值超出了接收类型的最大值就会变为 0

2.3.1 高低精度类型转换,精度丢失范例

1.我们先通过一个比较小的值来实现类型的转换

package main

import "fmt"

func main() {
    // 赋值 ua 值为 1
    var ua uint64 = 1

    // 强类型转换为 int8 并赋值给 i8
    i8 := int8(ua)

    // 转强类型转换为 uint64
    var ub uint64 = uint64(i8)
    fmt.Printf("i8=%d\n", i8)
    fmt.Printf("ub=%d\n", ub)
}

输出发现没有问题

[22:39:27 root@go day2]#go run main.go 
i8=1
ub=1

2.我通过下面的math.MaxUint64常量重新赋值给 ua 这个 uint64 类型

const math.MaxUint64 untyped int = 18446744073709551615
// math.MaxUint64 获取 uint64 类型最大值

编写代码

package main

import (
    "fmt"
    "math"
)

func main() {
    var ua uint64 = math.MaxUint64
    i8 := int8(ua)
    // 格式输出 %b 表示二进制
    fmt.Printf("i8=%d 二进制 = %b\n", ua, ua)
    var ub uint64 = uint64(i8)
    fmt.Printf("i8=%d 二进制 = %b\n", i8, i8)
    fmt.Printf("ub=%d\n", ub)
}

输出会发现 i8 的精度丢失问题,因为我们都知道 int8 的最大值是 127

[22:54:18 root@go day2]#go run main.go 
i8=18446744073709551615 二进制 = 1111111111111111111111111111111111111111111111111111111111111111
i8=-1 二进制 = -1              # 精度丢失,因为 int8 是一个带符号的,他把低 8 位结束了由此变为了负数
ub=18446744073709551615       # 这里又将 int8 强制转为 uint64

2.3.2 字符强制转换为 int

package main

import (
    "fmt"
)

func main() {
    // 这里将 A 字符强制转为 int
    var i int = int('A')
    fmt.Printf("%d\n", i)

    // 定义 s 字符串
    s := "abcd"
    for _, v := range s {
        // 通过 %d 格式化强制转换将 string 类型转为 int
        fmt.Printf("%d\n", v)
    }
}

输出

# 其实当我们将字符转为 int 类型的时候,就是转为了对应的 十进制 ASCII 码
[22:56:59 root@go day2]#go run main.go 
65
97
98
99
100
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇