Go语言学习之路-3-Go基本数据类型

什么是数据类型

数据是放在内存中的,变量是给这块内存起的名字,有了变量就可以找到并使用这份数据。

package main

import "fmt"

var (
	a int = 16
)

func main() {
	fmt.Println(a)
}

已知:计算机里都是0、1的组合,那为什么需要类型呢?

  • 00010000 该理解为数字16呢,还是字符串?如果没有特别指明,我们并不知道。
  • 内存中的数据有多种解释方式,使用之前必须要确定;上面的int a;就表明,这份数据是整数,不能理解为像素、声音等。int 有一个专业的称呼,叫做数据类型(Data Type)
  • 顾名思义,数据类型用来说明数据的类型,确定了数据的解释方式,让计算机和程序员不会产生歧义。

整型(整数)

按照有无符号可以分为两种,有符号整型(正整数(1,2,3,4.....)、负整数(-1,-2,-3,-4.....)各占一半),无符号整型(全是正整数)【正整数和负整数小学6年级学的】

无符号整数:
uint8、uint16、uint32、uint64
有符号整数:
int8、int16、int32、int64

这里的uint8、uint16、uint32、uint64和int8、int16、int32、int64 中的数字:8,16,32,64 分别代表的2的N次方

整型取值

类型 取值范围
uint8 8位 无符号 (0 到 255)
uint16 16位 无符号 (0 到 65535)
uint32 32位 无符号 (0 到 4294967295)
uint64 64位 无符号 (0 到 18446744073709551615)
int8 8位 有符号 (-128 到 127)
int16 16位 有符号 (-32768 到 32767)
int32 32位 有符号 (-2147483648 到 2147483647)
int64 64位 有符号 (-9223372036854775808 到 9223372036854775807)

特殊类型

类型 取值范围
uint 32位操作系统上就是uint32,64位操作系统上就是uint64
int 32位操作系统上就是int32,64位操作系统上就是int64
uintptr 无符号整型,用于存放一个指针

go语言中使用int

数字字面量语法(Number literals syntax)

字面量:可以理解为某种类型的值固定表达方式,类似我们看到鸭子的模样就知道它是一只鸭子(表面的样子)
18 就是数字
"Hello World" 就是字符串

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

package main

import "fmt"

var (
	// 二进制以0b开头
	a int = 0b00000001
	// 八进制以0开头
	b int = 071
	// 十六进制以0x开头
	c int = 0xABCDEF111
)

func main() {
	// 二进制以: 0b开头
	fmt.Println(a, b, c)
}

浮点型(小数)

Go语言支持两种浮点型数:float32和float64。这两种浮点型数据格式遵循IEEE 754标准

  • float32
  • float64

float32 的浮点数的最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32。 float64 的浮点数的最大范围约为 1.8e308,可以使用一个常量定义:math.MaxFloat64

package main

import (
    "fmt"
)

var (
    pi float64 = 3.141592653589793
)

func main() {
    fmt.Println(pi)
}

复数

package main

import (
    "fmt"
)

var z complex128

func main() {
    z = 3 + 2i
    x := real(z)
    y := imag(z)
    fmt.Println(x, y)
}

Go语言提供了两种精度的复数类型:complex64和complex128,分别对应float32和float64两种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实部和虚部
复数也可以用==和!=进行相等比较。只有两个复数的实部和虚部都相等的时候它们才是相等的。 math/cmplx包提供了复数处理的许多函数,例如求复数的平方根函数和求幂函数

一般情况真用不到,用到在看也不晚

有一篇文章挺好可以看下里面讲了一些应用场景应用场景: 复数的应用场景

布尔值(true false)

Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true(真)和false(假)两个值。

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

字符串

1 Go语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(int、bool、float32、float64 等)一样
2 内部实现使用的编码为utf-8
3 字符串通过""(双引号定义),这里需要注意其他语言有双引号和单引号都标识字符串,在go里双引号和单引号数据类型不一样
4 可以通过字面量直接定义

package main

import (
    "fmt"
)

func main() {
    name := "Hello World --> 你好世界"
    fmt.Println(name)
}

字符串转义

在字符串里面,有一些特殊的字符串组合有特殊意义(转义符)需要注意下

|转义符 |含义 |
|\r |回车符(返回行首) |
|\n |换行符(直接跳到下一行的同列位置) |
|\t |制表符 |
|\'| 单引号(单引号有特殊含义需要通过\来取消它的特殊含义) |
|\" |双引号(同上) |
|\\ |反斜杠(同上) |

package main

import (
    "fmt"
)

func main() {
    // 通过\把\转义 
    web := "http:\\\\www.sogou.com"
    fmt.Println(web)
    // 通过\n来重新开启一行
    code := "Hello World\n你好世界"
    fmt.Println(code)
}

多行字符串

Go语言中要定义一个多行字符串时,就必须使用反引号字符(`)包裹起来,并且反引号间所有的转义字符均无效,文本将会原样输出。

package main

import (
	"fmt"
)

func main() {
	// 通过\把\转义
	str := `
这里并没有被转义\t测试
   这里也并没有被转义\\\\n\\\\
hello    
`
	fmt.Println(str)
}

字符串常见操作

|方法 |方法描述 |
| len(str) | 字符串占用存储空间大小utf-8 字母特殊服务号占用1Byte 中文占用3~4个Byte【字符串常用操作-例子1】|
| +或fmt.Sprintf |字符串拼接【字符串常用操作-字符串拼接】|
|strings.Split |字符串切割【字符串常用操作-字符串切割】|
|strings.contains | 判断字符串是否包含某些字符串【字符串常用操作-字符串包含判断】|
| strings.HasPrefix,strings.HasSuffix |判断字符串是否以某个字符开头或结尾【字符串常用操作-字符串开头或结尾判断】|
| strings.Index(),strings.LastIndex() |判断字符第一次出现的位置和最后一次出现的位置【字符串常用操作-获取字符出现的位置】|
| func strings.Join(elems []string, sep string) string| 切片拼接为字符串 |

字符串常用操作-知识点:bit、字符

字母: a、b、c、d这种事字符,字符在对我们来说他是一个符号(具有某些意义的图形)

因为计算机是美国发明的,并且计算机只有两种状态通电和断电,可以用0和1表示,用0101的组合表示不同的字符

  • 所以用0101的组合表示美国的字符:a、b、c、d
  • 01010的组合 和 a、b、c、d、1 有一个对应表格叫做ASII吗
  • 8个0和1的组合就能表示所有英文字母和特殊符号,8bit(位) = 1B(字节) 1个字节=8bit是标准化产物

常用的对应表

  • ASII码就占用1个字节表示1个字符
  • Unicode码:4个字节表示一个字符(万国码)
  • UTF8吗:可变长的最少占用1个字节(比如ASII码就存1个字节)、最多占用4个字节中文就最多用4个字节表示(目前用的最多的)

字符串常用操作-字符串拼接

package main

import (
	"fmt"
)

func main() {
	// 字符串拼接
	str1, str2 := "hello ", "世界"
	// 字符串拼接方法1  通过: + 号
	combineStr1 := str1 + str2
	fmt.Println(combineStr1)
	// 字符串拼接方法2  通过:
	combineStr2 := fmt.Sprintf("%s%s", str1, str2)
	fmt.Println(combineStr2)
}

字符串分隔

package main

import (
	"fmt"
	"strings"
)

func main() {
	// 字符串分隔
	str := "hello 世 界"
	// Split接收两个内容第一个是你要切割的字符串,第二个填写切割字符串的规则比如我这个是根据空格符号分隔
	strList := strings.Split(str, " ")
	fmt.Println(strList, len(strList))
}

字符串常用操作-字符串包含判断

package main

import (
	"fmt"
	"strings"
)

func main() {
	// 字符串分隔
	str := "hello 世界"
	fmt.Println(strings.Contains(str, "世界"))
}

// 输出结果:true    真的说明是包含的

字符串常用操作-字符串开头或结尾判断

package main

import (
	"fmt"
	"strings"
)

func main() {
	str := "hello 世界"
	// 判断是否以: hell开头
	fmt.Println(strings.HasPrefix(str, "h"))
	// 判断是否以: 世界结尾
	fmt.Println(strings.HasSuffix(str, "世界"))
}

字符串常用操作-获取字符出现的位置

package main

import (
	"fmt"
	"strings"
)

func main() {
	str := "hello world!"
	// 以0开头的第一个o出现的位置
	fmt.Println(strings.Index(str, "o"))
	// 以0开头最后一次o出现的位置
	fmt.Println(strings.LastIndex(str, "o"))
}

// 输出结果:4
// 输出结果:7

byte和rune

组成字符串的每个元素叫做字符,如上面说过的h,l,世,界
在go中字符以:单引号(')

package main

import "fmt"

func main() {
	var s1 byte = 'a'
	var s2 rune = 'a'
	fmt.Printf("s1的类型:%T, s2的类型:%T", s1, s2)
	// 输出结果
	// s1的类型:uint8, s2的类型:int32
}

从上面的s1和s2的类型输出结果可以看出来,byte类型其实就unit8的别名,rune类型其实就是int32的别名

那为什么不直接用unit和int32来直接表示byte和rune呢?

目的提高代码的可读性,一看byte和rune类型就知道处理字符类型

好奇的遍历字符串

package main

import "fmt"

func main() {
	s1 := "hello 世界"
	fmt.Printf("字符串长度:%d\n", len(s1))
	fmt.Println("字符串循环内容如下:")
	for i := 0; i < len(s1); i++ {
		fmt.Println(s1[i])
	}
}

//  输出结果
/*
字符串长度12
字符串循环内容如下:
104
101
108
108
111
32
228
184
150
231
149
140
*/

刚开始的时候很多人会蒙什么情况,算上空格才8个字符怎么输出了真么多,而且还是输出的10进制的数字

  • 104其实就是h的ASCII码表的值 http://ascii.911cha.com/ 搜索104看看(ASCII表里小写的h)
  • 字符串底层是可以理解为通过byte存储的(为什么不直接用rune,byte一个占8位,rune1个占32位那个省空间?)

解决办法,两种方式

  • 建议通过for range range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身
  • 把字符串转为rune
package main

import "fmt"

func main() {
    s := "hello 世界"
// range 方式 - 建议
    for _, v1 := range s {
        // %v 值的默认格式表示
        // %c 该值对应的unicode码值
        fmt.Printf("value:%v,unicode:%c\n", v1, v1)
    }

    // 转换为rune方式
    s2 := []rune(s)
    for b := 0; b < len(s2); b++ {
        fmt.Printf("value:%v,unicode:%c\n", s2[b], s2[b])
    }
}

修改字符串

字符串创建后就是只读的(暂时不要去深究它),如果想修改它的内容需要转换成byte或者rune类型,完成后再转换为string。无论哪种转换,都会重新分配内存。

package main

import (
	"fmt"
)

func main() {
	x := "hello s"

	// 第一种方式先转换为byte类型
	x1 := []byte(x)
	x1[6] = '1' // 这里注意是单引号(')因为我们要替换一个字符
	fmt.Println(string(x1))

	// 第二种方式转换为rune类型
	y := "hello世界"
	y1 := []rune(y)
	y1[6] = '博' // 这里注意是单引号(')因为我们要替换一个字符
	fmt.Println(string(y1))

}

类型转换

  • 不能隐式的类型转换,只能显示的进行类型转换
  • 同一代码块内,当一个变量定义类型后,不能对相同变量进行类型转换
package main

import "fmt"

func main() {
    var x float64 = 0.1
    var y int = 1
    var h int = 104
    // 一个变量定义后,不可以重新对该变量赋值为其他类型:y = float64(y)  会报错
    // 只能在表达式中进行,强制类型转换,用于执行某一段代码
    c := x + float64(y)
    fmt.Println(c)

    fmt.Printf("%v,%T\n", y, y)
    // println也是一个表达式
    fmt.Println(string(h))
}

格式化输出

int类型格式化输出

package main

import (
	"fmt"
)

var (
	// 十进制
	a int = 100
	// 二进制以0b开头
	b int = 0b000000001
	// 八进制以0开头
	c int = 077
	// 十六进制以0x开头0-9,a-f
	d int = 0x123abcef10
)

func main() {
	// 通过格式化的输出可以输出其对应的进制值
	// 格式化输出使用fmt.Printf,这里面%d,%b,%o,%x,分别占用了一个位置(也就占位符),等着后面的a,b,c,d的变量值去替换
	// %d 整数的占位符
	// %b 二进制占位符
	// %o 八进制占位符
	// %x 16进制占位符
	fmt.Printf("格式化输出结果:%d,%b,%o,%x\n", a, b, c, d)
	// 如果直接输出的话会被默认转成10进制的
	fmt.Println("格式化输出结果:", a, b, c, d)
}

小数格式化输出

package main

import (
    "fmt"
)

var (
    pi = 3.1415926111111
)

func main() {
    // 小数的占位符%f 默认它是保留6位小数点
    fmt.Printf("格式化输出结果:%f\n", pi)
    // 可以通过%.2f 设置保留的小数.后面的数字,如%2.f就是保留2位小数
    fmt.Printf("格式化输出结果:%.2f\n", pi)
}

// 格式化输出结果:3.141593
// 格式化输出结果:3.14

布尔值格式化输出

package main

import (
	"fmt"
)

var z complex128

func main() {
	a := 3 > 10
	fmt.Printf("%t", a)
}

输出值得类型

import "fmt"

func main() {
	var x float64 = 0.1
	var y int = 1

	fmt.Printf("x类型:%T, y类型:%T", x, y)
}
posted @ 2020-03-30 23:10  天帅  阅读(380)  评论(0编辑  收藏  举报