基本数据类型

一、golang之基本数据类型

  • 共有6大基本数据类型
    • 整型
    • 浮点型
    • 复数类型
    • 布尔类型
    • 字符串类型
    • 字符相关的byte和rune类型

二、整型

  • 按有无符号分为两类,说白了就是有符号的包含负数、无符号不含
  • 如有符号的int8类型范围是 (-128 到 127) 的整数,而无符号的uint8类型范围是(0~255)的整数

1. 有符号(范围是负数、0和正数)

  • int8、int16、int32、int64,后面的数字表示二进制时的长度

  • 其中,uint8就是我们熟知的byte型,int16对应C语言中的short型,int64对应C语言中的long型。

  • 例子: int8范围是 (-128 到 127) 的整数,负数比正数多一个

2. 无符号(范围是0和正数)

  • uint8、uint16、uint32、uint64

  • 例子:uint8范围是 (0 到 255) 的整数

3. 特殊整型

  1. uint : 32位操作系统上就是uint32,64位操作系统上就是uint64
  2. int: 32位操作系统上就是int32,64位操作系统上就是int64
  3. uintptr: 无符号整型,用于存放一个指针
  • 注意: 在使用intuint类型时,不能假定它是32位或64位的整型,而是考虑intuint可能在不同平台上的差异。

4. 数字字面量语法(先了解就好)

  • Go1.13版本之后引入了数字字面量语法 , 这样便于开发者以二进制、八进制或十六进制浮点数的格式定义数字 。共四种表示。

  • 实例

    1. v := 0b00101101, 代表二进制的 101101,相当于十进制的 45
    2. v := 0o377,代表八进制的 377,相当于十进制的 255
    3. v := 0x1p-2,代表十六进制的 1 除以 2²,也就是 0.25
    4. v := 123_456 等于 123456
    

三、浮点型

  • Go语言支持两种浮点型数:float32float64

  • 浮点型和整型的变量直接不能直接相加,需要转换一边的格式成两边相同格式,但是在一个数字表达式中,却可以直接计算

    1. 定义浮点型
    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        a, b := 5.67, 8.97
        fmt.Printf("type of a %T b %T\n", a, b)
        sum := a + b
        diff := a - b
        fmt.Println("sum", sum, "diff", diff)
    
        no1, no2 := 56, 89
        fmt.Println("sum", no1+no2, "diff", no1-no2)
    }
    
    /* 
    打印结果:
    type of a float64 b float64  
    sum 14.64 diff -3.3000000000000007  
    sum 145 diff -33 
    */
    
    2. 浮点型变量和整型变量间的计算
    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        i := 55      //int
        j := 67.8    //float64
        sum := i + int(j) // 将j转换成int型
        fmt.Println(sum)
    }
    
    
    3. 数字表达式计算
    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        var a = 5.9/8  // 可以这样定义
        fmt.Printf("a's type %T value %v",a, a)
    }
    
    // 打印结果:  a's type float64 value 0.7375
    
    

三、复数类型

  • 分为complex64complex128
    • complex64:实部和虚部都是 float32 类型的的复数

    • complex128:实部和虚部都是 float64 类型的的复数

1. 定义复数

1. 内置函数 complex 用于创建一个包含实部和虚部的复数。complex 函数的语法如下:
complex(x, y)  // 表示定义一个实部为x,虚部为y的复数

2. 简短定义

a := 5 + 6i  // 表示定义了一个实部为5,虚部为6的复数

2. 实例

package main

import (  
    "fmt"
)

func main() {  
    c1 := complex(5, 7)
    c2 := 8 + 27i
    cadd := c1 + c2
    fmt.Println("sum:", cadd)
    cmul := c1 * c2
    fmt.Println("product:", cmul)
}

/*在上面的程序里,c1 和 c2 是两个复数。c1的实部为 5,虚部为 7。c2 的实部为8,虚部为 27。c1 和 c2 的和赋值给 `cadd` ,
而 c1 和 c2 的乘积赋值给 `cmul`。该程序将输出:*/

sum: (13+34i)   product: (-149+191i)

四、布尔类型

  • 同其他语言一样,就是两个布尔值truefalse

  • 注意:

    • 布尔类型变量的默认值为false
    • 语言中不允许将整型强制转换为布尔型
    • 布尔型无法参与数值运算,也无法与其他类型进行转换。

五、字符串类型

  • Go 语言中的字符串是一个字节切片

  • Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码

  • 字符串的值为双引号内的内容

  • 关于字符串的其他的操作,见下面的第六点:字符相关的byterune类型

  • Go 中的字符串是不可变的。一旦一个字符串被创建,那么它本身将无法被直接修改,但是可以通过其他方法修改

1. 常见的字符串转义符

转义符 解释
\r 回车符(返回首行)
\n 换行符(跳到下一行的同列位置)
\t 制表符
\' 单引号
\" 双引号
\\ 反斜杠

2. 多行字符串

  • 用反引号引住即可

    // 单行字符串
    s1 := "字符串内容"
    
    // 多行字符串
    s1 := `第一行
    第二行
    第三行
    `
    
  • 反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。

3. 字符串常用的方法

(1)字符串长度

  • len方法返回的结果是字符串的utf8的字节长度,所以在处理当需要处理中文、日文或者其他复合字符时,会出现字符长度和字符串的字符长度不等的情况

  • 此时用 [utf8 package] 包中的 func RuneCountInString(s string) (n int) 方法用来获取字符串的长度

    • package main
      
      import (  
          "fmt"
          "unicode/utf8"
      )
      
      func length(s string) {  
          fmt.Printf("RuneCountInString 函数 求得的长度为 %s is %d\n", s, utf8.RuneCountInString(s))
      }
      
      func len_get(s string) {
          fmt.Printf("len 函数 求得的长度为 %s is %d\n", s, len(s))
      }
      
      func main() { 
          word1 := "Señor" 
          length(word1)
          len_get(word1)
          word2 := "Pets"
          length(word2)
          len_get(Pets)
      }
      
      /*
      RuneCountInString 函数 求得的长度为 Señor is 5
      len 函数 求得的长度为 Señor is 6             
      RuneCountInString 函数 求得的长度为 Pets is 4
      len 函数 求得的长度为 Pets is 4 
      */
      

(2)其他字符串常用方法

方法 介绍
len(str) len() 返回字符串中字节的数量
+或fmt.Sprintf 拼接字符串
strings.Split 分割
strings.contains 判断是否包含
strings.HasPrefix,strings.HasSuffix 前缀/后缀判断
strings.Index(),strings.LastIndex() 子串出现的位置
strings.Join(a[]string, sep string) join操作

六、字符相关的byterune类型

  • Go 语言的字符有两种 :即byte 和 rune类型

  • 字符串的每个元素就叫做字符。可以通过遍历或单个获取字符串中的字符。

  • 字符使用单引号包裹起来

  • 实例

    a := '中'
    b := 'x'
    fmt.Println(a, b)  // 20013 120
    

1. byte

  • byte 型是 uint8 类型的别名,代表了ASCII码的一个字符

  • Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾

2. rune

  • rune 是 Go 语言的内建类型,它也是 int32 的别称,代表一个 UTF-8字符 (注意是字符,一个汉字、一个字母都是一个字符)

  • 当需要处理中文、日文或者其他复合字符时,则需要用到rune类型

3. 总结(byterune的对比)

  • Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾

  • 实例

    // 遍历字符串
    func traversalString() {
        s := "hello沙河";
        for i := 0; i < len(s); i++ { // byte
            fmt.Printf("%v(%c) ", s[i], s[i])
        }
        fmt.Println()
        for _, r := range s {  // rune
            fmt.Printf("%v(%c) ", r, r)
        }
        fmt.Println()
    }
    
    打印结果:
    
    // 104(h) 101(e) 108(l) 108(l) 111(o) 230(æ) 178(²) 153() 230(æ) 178(²) 179(³)
    
    // 104(h) 101(e) 108(l) 108(l) 111(o) 27801(沙) 27827(河) 
    
  • 因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面实例中输出中第一行的结果

  • go语言的字符串和python中的字符串类似, 底层都是一个byte数组 ,所以字符串的长度就是其二进制的长度,并且他们可以直接转换成二进制格式即[]byte类型。

  • **rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成 **

4. 遍历字符串中的单个字符

  • 由于字符串是一个字节切片,所以我们可以获取字符串的每一个字节

  • 有两种方法

    • 一个是手动转化后遍历(不转化会有bug)
    • 一个是用 for range 遍历(推荐)

(1)手动转化后遍历

  • 由于go中的字符有 runebyte 类型两种,所以,有的字符在打印的时候会出现和我们预期的不符和

    • package main
      
      import (
          "fmt"
      )
      
      func printBytes(s string) {
          for i:= 0; i < len(s); i++ {
              fmt.Printf("%x ", s[i])  // %x 格式限定符用于指定 16 进制编码的byte类型
          }
      }
      
      func printChars(s string) {
          for i:= 0; i < len(s); i++ {
              fmt.Printf("%c ",s[i])  // %c 格式限定符用于打印字符串的字符
          }
      }
      
      func main() {
          name := "Hello World"
          printBytes(name)
          fmt.Printf("\n")
          printChars(name)
          fmt.Printf("\n")
          name = "Señor"
          printBytes(name)
          fmt.Printf("\n")
          printChars(name)
      }
      
      /*
      打印结果
      
      48 65 6c 6c 6f 20 57 6f 72 6c 64  
      H e l l o   W o r l d  
      53 65 c3 b1 6f 72  
      S e à ± o r
      
      这里的字符 ñ 在打印结果中,变成了 Ã ± 两个字符,在上一行的16进制编码byte类型中显示 ñ 占用了 c3 b1 两个字节,所以才打印了 Ã ± 两个字符 。
      而我们通常预期的是:字符串中的一个字符应该就打印一个字符,这就造成了实际打印结果和我们的预期对不上
      解决方法是使用 rune 类型进行字符串的转换,转换之后再进行字符的遍历,转换的代码如下
      */
      
      package main
      
      import (
          "fmt"
      )
      
      func printBytes(s string) {
          for i:= 0; i < len(s); i++ {
              fmt.Printf("%x ", s[i])
          }
      }
      
      func printChars(s string) {
          runes := []rune(s)  // 这里将字符串 s 转化成一个 rune 切片
          for i:= 0; i < len(runes); i++ {
              fmt.Printf("%c ",runes[i])
          }
      }
      
      func main() {
          name := "Hello World"
          printBytes(name)
          fmt.Printf("\n")
          printChars(name)
          fmt.Printf("\n\n")
          name = "Señor"
          printBytes(name)
          fmt.Printf("\n")
          printChars(name)
      }
      
      /* 
      打印结果,符合预期
      
      48 65 6c 6c 6f 20 57 6f 72 6c 64  
      H e l l o   W o r l d 
      
      53 65 c3 b1 6f 72  
      S e ñ o r
      */
      

(2)for range 遍历

  • range 内部给我们做了转化,返回的是是当前 rune 的字节位置
  • **rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成(即一个rune字符可以代表多个字节) **
package main

import (
    "fmt"
)

func printCharsAndBytes(s string) {
    for index, rune_s := range s {
        fmt.Printf("%c starts at byte %d\n", rune_s, index)
    }
}

func main() {
    name := "Señor"
    printCharsAndBytes(name)
}

/*
S starts at byte 0  
e starts at byte 1  
ñ starts at byte 2  
o starts at byte 4  
r starts at byte 5

o 的索引跳过了3直接变成了4,所以可以推断出 ñ 占了两个字节
*/

5. 修改字符串

  • Go 中的字符串是不可变的。一旦一个字符串被创建,那么它将无法被修改

  • 要修改字符串,需要先将其转换成[]rune切片或[]byte切片,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组

  • 实例

    func changeString() {
        s1 := "big"
        // 强制类型转换
        byteS1 := []byte(s1)
        byteS1[0] = 'p'
        fmt.Println(string(byteS1))  // "pig"
    
        s2 := "白萝卜"
        runeS2 := []rune(s2)
        runeS2[0] = '红'
        fmt.Println(string(runeS2))  // "红萝卜"
    }
    

6. 构造字符串

  • 两种构造方式

    • 字节切片构造字符串

    • rune 切片构造字符串

(1)字节切片构造字符串

// 构造复合字符串 Café

1. 通过16进制字节切片构造

package main

import (  
    "fmt"
)

func main() {  
    byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}  // 用utf8的16进制的字节切片,转化成字符串
    str := string(byteSlice)
    fmt.Println(str)  // 打印结果:cafe
}

2. 通过10进制字节切片构造

package main

import (  
    "fmt"
)

func main() {  
    byteSlice := []byte{67, 97, 102, 195, 169}  // 用utf8的10进制的字节切片,转化成字符串
    str := string(byteSlice)
    fmt.Println(str)
}

两个程序都输出了 字符串 Café 
***********由此可见,utf8编码的不同进制数的字节切片对构造字符串无影响***********

(2)rune切片构造字符串

package main

import (  
    "fmt"
)

func main() {  
    runeSlice := []rune{0x0053, 0x0065, 0x00f1, 0x006f, 0x0072}
    str := string(runeSlice)
    fmt.Println(str)
}

// 在上面的程序中 runeSlice 包含字符串 Señor的 Unicode编码下的 16 进制的 字节串 。这个程序将会输出Señor

七、类型转换

  • Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用

  • 强制类型转换的基本语法

    T(表达式)
    
    // T表示要转换的类型 ,表达式包括变量、复杂算子和函数返回值等.
    
  • 强制类型转换实例

    1. 例1
    func sqrtDemo() {
        var a, b = 3, 4
        var c int
        // math.Sqrt()接收的参数是float64类型,需要强制转换
        c = int(math.Sqrt(float64(a*a + b*b)))
        fmt.Println(c)
    }
    
    2. 例2
    
    func main() {  
        i := 10
        var j float64 = float64(i) // 若没有显式转换,该语句会报错
        fmt.Println("j", j)
    }
    
    
posted @ 2019-12-01 19:47  BigSun丶  阅读(315)  评论(0)    收藏  举报