• 8、数据结构-字符串、编码集


    编码表

    中文编码表

    ​ 数字到中文单一字符的映射,汉字只能使用多字节的2字节,总有65535种状态。常见的中文编码有GB2312 、GBK 、GB18030 、BIG 5。

    ​ 所有编码表都兼容单字节的ASCII表

    UNICODE

    ​ 多字节,一张编码表解决全球多数字符对应问题

    ​ 表示汉字多数使用2个字节

    ​ Go中’x’方式,保存int32 rune整数值,%c打印通过Unicode编码表找到字符输出

    ​ 因为字符是int32 rune类型,所以是4字节,但是汉字只占2个字节

    func main() {
    	var s1 = 'x'
    	fmt.Println(s1)
    	fmt.Printf("%c", s1)
    
    }
    120
    x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    UTF-8

    ​ 多字节

    ​ 汉字转化为3个字节

    ​ utf8mb4

    ​ 字符串,字符序列,每个汉字就是utf8编码的,也就是汉字是3个字节

    乱码问题:编码和解码用得不是一套编码表

    ASCII

    在这里插入图片描述

    ascii码总有有 128位,用来表示常用的字符。

    在这里插入图片描述

    注意:这里的1指的是字符1,不是数字1

    UTF-8、GBK都兼容了ASCII

    "a\x09b\x0ac \x31\x20\x41\x61" 表示什么?
    "a	b
    c 1 Aa"
    
    • 1
    • 2
    • 3
    'A' > 'a'  谁大?字符比较
    	if 'A' > 'a' {
    		fmt.Println("A大")
    	} else {
    		fmt.Println("a大")
    	}
    a大		本质比较的是在ascii中A和a对应的编码值
    
    "a" > "A"  谁大?字符串比较 同上
    "AA" > "Aa" 谁大?先比较第一位,第一位相同在比较第二位
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    字符

    ​ 本质上来说,计算机中一切都是字节的,字符串也是多个字节组合而成,就是多个字节形成的有序序列。但是对于多字节编码的中文来说,用一个字节描述不了,需要多个字节表示一个字符,Go提供了rune类型。

    • byte:兼容ASCII码的字符,是byte类型,即uint8别名,占用1个字节
    • rune: 汉字等字符,unicode编码,是rune类型,即int32别名,占用4个字节
    • 一个字符字面量使用单引号引起来

    字符串与字节序列的转换

    func main() {
    	s1 := "abc"
    	s2 := "测试"
    	fmt.Println(len(s1), len(s2))
    }
    3 6 
    //结论:在字符串中,中文一个汉字占3个字节
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // 强制类型转换 string => []byte; string => []rune
    // 注意[]byte表示字节序列;[]rune表示rune序列
    func main() {
    	s1 := "abc"
    	 s2 := "测试"
    	fmt.Println([]byte(s1))
    	fmt.Println([]rune(s1))
    }
    [97 98 99]
    [97 98 99]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    func main() {
    	s2 := "测试" 
    	fmt.Println([]byte(s2))		 // utf-8 bytes,长度为6即6个字节
    	fmt.Println([]rune(s2))		// unicode切片,长度为2,每个元素4字节
    }
    [230 181 139 232 175 149]
    [27979 35797]
    //结论:汉字转字节  在字符串中,一个汉字对应3个字节 所以测试是6个字节
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    func main() {
    	fmt.Printf("%x, %x\n", 27979, 35797) //转16进制
    	fmt.Printf("%c%c\n", 27979, 35797)
    
    }
    6d4b, 8bd5   
    测试
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // []byte => string
    func main() {
    	fmt.Println(string([]byte{49, 65, 97}))
    }
    1Aa 
    //结论:在ASCII中查询对应的值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    // []rune => string
    测试
    //结论:rune使用unicode,但是字符串内部使用utf-8
    
    • 1
    • 2
    • 3

    重点

    func main() {
    	var s2 = "测试"
    	fmt.Println(s2[0], s2[1], s2[2])
    }
    230 181 139
    //结论:是按照字节的形式取出来的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    string(一个整数),强制类型转换一个整数,相当于把整数当unicode码,去查一个字符,最后返回
    字符串
    string(整数序列),强制类型转换一个整数序列,也是转成字符串

    字符串

    • 字面常量,只读,不可变
    • 线性数据结构,可以索引
    • 值类型
    • utf-8编码

    长度

    ​ 使用内建函数len,返回字符串占用的字节数。时间复杂度为O(1),字符串是字面常量,定义时已经知道长度,记录下来即可

    索引

    ​ 不支持负索引,索引范围[0, len(s)-1]。

    ​ 即使是有中文,索引指的是按照 字节的偏移量。

    ​ 时间复杂度O(1),使用索引计算该字符相对开头的偏移量即可。

    ​ 对于顺序表来说,使用索引效率查找效率是最高的。

    ​ s[i] 获取索引i处的UTF-8编码的一个字节。

    遍历

    C风格使用索引遍历,相当于字节遍历

    func main() {
    	s := "ZFL努力学习编程"
    	for i := 0; i < len(s); i++ {
    		fmt.Printf("%d, %T, %[2]d %[2]c\n", i, s[i])
    	}
    }
    0, uint8, 90 Z
    1, uint8, 70 F
    2, uint8, 76 L
    3, uint8, 229 å
    4, uint8, 138 Š
    5, uint8, 170 ª
    6, uint8, 229 å
    7, uint8, 138 Š
    8, uint8, 1559, uint8, 229 å
    10, uint8, 173 ­
    11, uint8, 166 ¦
    12, uint8, 228 ä
    13, uint8, 185 ¹
    14, uint8, 160  
    15, uint8, 231 ç
    16, uint8, 188 ¼
    17, uint8, 15018, uint8, 231 ç
    19, uint8, 168 ¨
    20, uint8, 139//这是以字节遍历的 因为汉字是3个字节 所以后面的%c会看不懂
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    func main() {
    	s := "ZFL努力学习编程"
    	for i, v := range s {
    		fmt.Printf("%d: %[3]d %[3]c\n", i, s[i], v)
    	}
    }
    0: 90 Z
    1: 70 F
    2: 76 L
    3: 211626: 211479: 2339812: 2006415: 3253418: 31243//结论:高级for循环是遍历字符的。   因为字符是rune类型,所以查找表,将对应的值输出来
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    strings库

    字符串是字面常量,不可修改,很多操作都是返回新的字符串

    拼接

    常用的四种:

    • join:使用间隔符拼接字符串切片
    • Builder:多次拼接,推荐
    • fmt.Sprintf:方便快捷,推荐
    • 直接通过+来拼接
    func main() {
    	s0 := "zfl"
    	s1 := "努力学习编程"
    	s2 := s0 + s1
    	fmt.Println(s2)
    }
    zfl努力学习编程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    func main() {
    	s0 := "zfl"
    	s1 := "努力学习编程"
    	s3 := strings.Join([]string{s0, s1}, "")
    	fmt.Println(s3)
    }
    zfl努力学习编程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    func main() {
    	s0 := "zfl"
    	s1 := "努力学习编程"
    	s4 := fmt.Sprintf("%s%s\n", s0, s1)
    	fmt.Println(s4)
    }
    zfl努力学习编程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //多次拼接
    func main() {
    	s0 := "zfl"
    	s1 := "努力学习编程"
    	var b strings.Builder
    	b.WriteString(s0)
    	b.WriteByte('-')
    	b.WriteString(s1)
    	s5 := b.String()
    	fmt.Println(s5)
    }
    zfl-努力学习编程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    结论:简单拼接字符串常用+、fmt.Sprintf。如果手里正好有字符串的序列,可以考虑Join。如果反复多次拼接,strings.Builder是推荐的方式。

    查询

    • Index:从左至右搜索,返回子串第一次出现的字节索引位置。未找到,返回-1。子串为空,也返回0。
    • LastIndex:从右至左搜索,返回子串第一次出现的字节索引位置。未找到,返回-1。
    • IndexByte、IndexRune与Index类似;LastIndexByte与LastIndex类似。
    • IndexAny:从左至右搜索,找到给定的字符集字符串中任意一个字符就返回索引位置。未找到返回-1。
    • Contains方法本质上就是Index方法,只不过返回bool值,方便使用bool值时使用。
    • LastIndexAny与IndexAny搜索方向相反。
    • Count:从左至右搜索子串,返回子串出现的次数

    时间复杂度是O(n),效率不高,该用则用,但要少用。>

    //Index:从左至右搜索,返回子串第一次出现的字节索引位置。未找到,返回-1。子串为空,也返回0。
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.Index(s0, "学"))
    
    }
    9
    结论:一个汉字三个字节,所以为9
    ​~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.Index(s0, "学"))
    	fmt.Println(strings.Index(s0, "龙"))
    }
    -1
    ​~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.Index(s0, "学"))
    	fmt.Println(strings.Index(s0, ""))
    }
    0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    //LastIndex:从右至左搜索,返回子串第一次出现的字节索引位置。未找到,返回-1。
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.LastIndex(s0, "学"))
    	fmt.Println(strings.LastIndex(s0, "龙"))
    }
    9
    -1
    结论:索引号是不变的 虽然从右到左,但是也仍旧是左到右的索引
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    //IndexByte、IndexRune与Index类似;LastIndexByte与LastIndex类似。
    //IndexAny:从左至右搜索,找到给定的字符集字符串中任意一个字符就返回索引位置。未找到返回-1
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.IndexAny(s0, "学l"))
    }
    2
    结论:只要找到学或者l任意的一个 直接就返回索引值 先找到谁直接返回  不在继续找
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println([]byte("学"))
    	fmt.Println([]rune("学"))
    	fmt.Println(strings.IndexByte(s0, 173))
    	fmt.Println(strings.IndexRune(s0, 23398))
    }
    [229 173 166]
    [23398]
    10
    9
    结论:从做到右通过码点来找
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    //Contains*方法本质上就是Index*方法,只不过返回bool值,方便使用bool值时使用。
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.Contains(s0, "习"))
    }
    true
    ​~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    func main() {
    	s0 := "zfl努力学习编程"
    	fmt.Println(strings.Contains(s0, "了"))
    }
    false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    //Count:从左至右搜索子串,返回子串出现的次数
    func main() {
    	s0 := "zfl好好努力学习编程"
    	fmt.Println(strings.Count(s0, "学"))
    	fmt.Println(strings.Count(s0, "好"))
    }
    1
    2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    大小写

    • ToLower:转换为小写
    • ToUpper:转换为大写
    
    func main() {
    	s0 := "ZFL"
    	s1 := "hello world"
    	fmt.Println(strings.ToLower(s0))
    	fmt.Println(strings.ToUpper(s1))
    }
    zfl
    HELLO WORLD
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    前后缀

    • HasPrefix:是否以子串开头
    • HasSuffix:是否以子串结尾
    func main() {
    	s0 := "zfl好好学习xyz"
    	fmt.Println(strings.HasPrefix(s0, "zfl"))
    	fmt.Println(strings.HasPrefix(s0, "zflxx"))
    	fmt.Println("~~~~~~~~~~~~~~")
    	fmt.Println(strings.HasSuffix(s0, "xyz"))
    }
    true
    false
    ​~~~~~~~~~~~~~~
    true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    移除

    • TrimSpace:去除字符串两端的空白字符。
    • TrimPrefix、TrimSuffix:如果开头或结尾匹配,则去除。否则,返回原字符串的副本。
    • TrimLeft:字符串开头的字符如果在字符集中,则全部移除,直到碰到第一个不在字符集中的字符为止。
    • TrimRight:字符串结尾的字符如果在字符集中,则全部移除,直到碰到第一个不在字符集中的字符为止。
    • Trim:字符串两头的字符如果在字符集中,则全部移除,直到左或右都碰到第一个不在字符集中的字符为止。
    //TrimSpace:去除字符串两端的空白字符。
    func main() {
    	s0 := "\v\n\r \tabc\txyz\t \v\r\n"
    	fmt.Println(strings.TrimSpace(s0))
    }
    abc	xyz
    结论:字符串两端的空白字符取掉,中间的不取
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //TrimPrefix、TrimSuffix:如果开头或结尾匹配,则去除。否则,返回原字符串的副本。
    func main() {
    	s0 := "zfl好好学习xyz"
    	fmt.Println(strings.TrimPrefix(s0, "zfl"))
    	fmt.Println(strings.TrimSuffix(s0, "xyz"))
    }
    好好学习xyz
    zfl好好学习
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //TrimLeft:字符串开头的字符如果在字符集中,则全部移除,直到碰到第一个不在字符集中的字符为止。
    //TrimRight:字符串结尾的字符如果在字符集中,则全部移除,直到碰到第一个不在字符集中的字符为止。
    func main() {
    	s0 := "abcdddeabeccc"
    	fmt.Println(strings.TrimLeft(s0, "abcd"))
    	fmt.Println(strings.TrimRight(s0, "abcd"))
    }
    eabeccc
    abcdddeabe
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    //Trim:字符串两头的字符如果在字符集中,则全部移除,直到左或右都碰到第一个不在字符集中的字符为止。
    func main() {
    	s0 := "abcdddeabeccc"
    	fmt.Println(strings.Trim(s0, "abcd"))
    }
    eabe
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    分割

    • Split:按照给定的分割子串去分割,返回切割后的字符串切片。
      • 切割字符串是被切掉的,不会出现在结果中
      • 没有切到,也会返回一个元素的切片,元素就是被切的字符串
      • 分割字符串为空串,那么返回将被切割字符串按照每个rune字符分解后转成string存入切片返回
    • SplitN(s, sep string, n int) []string ,n表示最终切片中有几个元素
      • n == 0,返回空切片,切成0个子串
      • n > 0,返回切片元素的个数
        • n == 1,返回一个元素切片,元素为s,相当于Split的没有切到
        • n > 1,按照sep切割。返回多个元素的切片。按照sep切成的段数最多有x段,当n < x
          时,会有部分剩余字符串未切;n == x时,字符串s正好从头到尾切完,返回所有段的切片;n > x时,和n == x一样。n表示切割出来的子串的上限,即至多切片里面有n个元素
        • n < 0,等价Split,能切多少切出多少
    • SplitAfter和Split相似,就是不把sep切掉
    • SplitAfterN和SplitN相似,也不把sep切掉
    • Cut(s, sep string) (before, after string, found bool)
      • 内部使用Index找sep,所以是从左至右搜索切割点。可以认为就是切一刀,一刀两段
      • 没有切到,返回 s, “”, false
      • 切到了,匹配切割符的部分要切掉,返回 切割符前部分,切割符后部分, true
    func main() {
    	s := "www.itzfl.com-好好学习"
    	var s1 = strings.Split(s, ".")   //声明以·切割
    	fmt.Println(s1)
    	fmt.Println(s1[0])
    }
    [www itzfl com-好好学习]
    www
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //没有切到,也会返回一个元素的切片,元素就是被切的字符串
    	s := "www.itzfl.com-好好学习"
    	var s1 = strings.Split(s, "=")
    [www.itzfl.com-好好学习]
    
    • 1
    • 2
    • 3
    • 4
    
    //分割字符串为空串,那么返回将被切割字符串按照每个rune字符分解后转成string存入切片返回
    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.Split(s, ""))
    }
    [w w w . i t z f l . c o m - 好 好 学 习]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //- SplitAfter和Split相似,就是不把sep切掉
    //- SplitAfterN和SplitN相似,也不把sep切掉
    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.SplitAfter(s, "."))
    	fmt.Println(strings.SplitAfter(s, "="))
    	fmt.Println(strings.SplitAfter(s, ""))
    }
    [www. itzfl. com-好好学习]
    [www.itzfl.com-好好学习]
    [w w w . i t z f l . c o m - 好 好 学 习]
    //结论:就是将切割符保留
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    //SplitN(s, sep string, n int) []string ,n表示最终切片中有几个元素
    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.SplitN(s, ".", 1))      // 返回的切片只能有1个元素
    	fmt.Println(strings.SplitN(s, ".", 2))      // 返回的切片只能有2个元素
    	fmt.Println(strings.SplitAfterN(s, ".", 2)) // 返回的切片只能有2个元素
    }
    [www.itzfl.com-好好学习]
    [www itzfl.com-好好学习]
    [www. itzfl.com-好好学习]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    //Cut(s, sep string) (before, after string, found bool)
    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.Cut(s, "."))
    }
    www itzfl.com-好好学习 true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    替换

    • Replace(s, old, new string, n int) string
      • n < 0,等价ReplaceAll,全部替换
      • n == 0,或old == new,就返回s
      • n > 0,至多替换n次,如果n超过找到old子串的次数x,也就只能替换x次了
      • 未找到替换处,就返回s
    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.Replace(s, "w", "l", 2))
    	fmt.Println(strings.Replace(s, "w", "l", 0)) //n == 0,或old == new,就返回s
    	fmt.Println(strings.Replace(s, "w", "l", 5)) //n > 0,至多替换n次,如果n超过找到old子串的次数x,也就只能替换x次了
    	fmt.Println(strings.Replace(s, "w", "l", -1)) //n < 0,等价ReplaceAll,全部替换
    }
    llw.itzfl.com-好好学习
    www.itzfl.com-好好学习
    lll.itzfl.com-好好学习
    lll.itzfl.com-好好学习
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其他

    Repeat:使用给定的字符串重复n次拼接成一个新字符串。

    Map:按照给定处理每个rune字符的函数依次处理每个字符后,拼接成字符串返回。注意Map是
    一对一的映射,不能减少元素个数。

    func main() {
    	s := "www.itzfl.com-好好学习"
    	fmt.Println(strings.Map(func(r rune) rune {
    		if 'a' <= r && r <= 'z' {
    			return r - 0x20 // 请问这是干什么?
    		}
    		return r
    	}, s))
        WWW.ITZFL.COM-好好学习
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    类型转换

    数值类型转换

    • 低精度向高精度转换可以,高精度向低精度转换会损失精度
    • 无符号向有符号转换,最高位是符号位
    • byte和int可以互相转换
    • float和int可以相互转换,float到int会丢失精度
    • bool和int不能相互转换
    • 不同长度的int和float之间可以互相转换
    func main() {
    	var i int8 = -1
    	var j uint8 = uint8(i)
    	fmt.Println(i, j) // 请问j是多少
    }
    -1 255
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    func main() {
    	fmt.Println(int(3.14))  // 错误,不允许无类型float常量转到int
    	var a = 3.14             // 定义有类型变量转换就没有问题
    	fmt.Printf("%T: %[1]v => %T %[2]d\n", a, int(a)) // float64: 3.14 => int 3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    func main() {
    	// byte rune本质上就是整数和无类型常量可以直接计算,自动转换
    	b := 'a'
    	c := b + 1
    	fmt.Printf("%T %[1]c %[1]d", c) // 请问c显示什么,什么类型}
    }
    int32 b 98
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    类型别名和类型定义

    var a byte = 'C'
    var b uint8 = 49
    fmt.Println(a, b, a+b) // 为什么类型不同,可以相加?
    原因是在源码中定义了 type byte = uint8byteuint8的别名。
    别名说明就是uint8的另外一个名字,和uint8是一回事
    
    • 1
    • 2
    • 3
    • 4
    • 5
    type myByte uint8
    var c myByte = 50
    fmt.Println(a, c, a + c) // 可以吗?为什么?
    答案是不可以。原因就是Go原因不允许不同类型随便运算。就算我们眼睛看到可以,也不行,必须强制
    类型转换,
    type myByte uint8 // 类型定义
    type byte = uint8 // 类型别名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    func main() {
    	type myByte = uint8
    	var a byte = 'C'
    
    	var c myByte = 50
    	fmt.Println(a, c, a+c)
    }
    67 50 117
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    }

    
    ~~~go
    func main() {
    	// byte rune本质上就是整数和无类型常量可以直接计算,自动转换
    	b := 'a'
    	c := b + 1
    	fmt.Printf("%T %[1]c %[1]d", c) // 请问c显示什么,什么类型}
    }
    int32 b 98
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    类型别名和类型定义

    var a byte = 'C'
    var b uint8 = 49
    fmt.Println(a, b, a+b) // 为什么类型不同,可以相加?
    原因是在源码中定义了 type byte = uint8byteuint8的别名。
    别名说明就是uint8的另外一个名字,和uint8是一回事
    
    • 1
    • 2
    • 3
    • 4
    • 5
    type myByte uint8
    var c myByte = 50
    fmt.Println(a, c, a + c) // 可以吗?为什么?
    答案是不可以。原因就是Go原因不允许不同类型随便运算。就算我们眼睛看到可以,也不行,必须强制
    类型转换,
    type myByte uint8 // 类型定义
    type byte = uint8 // 类型别名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    func main() {
    	type myByte = uint8
    	var a byte = 'C'
    
    	var c myByte = 50
    	fmt.Println(a, c, a+c)
    }
    67 50 117
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    Gerrrit 管理员常用命令
    串口通信及串口转蓝牙相关知识
    Linux系统中如何安装生信软件?保姆式全攻略
    FFmpeg入门详解之115:X264编码
    MySQL BufferPool缓存与Redo日志是如何提升事务性能的
    JavaWeb—系统架构
    GenericServlet、ServletConfig和ServletContext
    电商领域的三大沉疴难题?实在智能RPA来帮你药到病除!
    是谁的请求导致我的系统一直抛异常?
    Script file ‘F:.....\pip-script.py‘ is not present 原因及解决办法
  • 原文地址:https://blog.csdn.net/xiaolong1155/article/details/134393252