go 语言之基础数据类型

数据类型

Go 语言有丰富的数据类型,除了基本的整数、浮点型、布尔型、字符串之外,还有切片。结构体、函数、map、通道(channel)。Go 语言基本数据类型和其他语言大同小异,切片类型有着指针的便利性,但比指针更安全,很多高级语言都配有切片进行安全和高效率的内存操作

       结构体是go 语言基础的复杂类型之一,后面单独介绍;函数也是go语言的一种数据类型,可以对函数类型的变量进行赋值和获取,函数特性较多;map和切片是开发中常见的数据容器类型;通道与并发相关

整型

整型分为以下两个大类

按长度分为:int8、int16、int32、int64

还有对应的无符号整型:uint8、uint16、uint32、uint64

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

1. 自动匹配平台的int和uint

     go语言也有自动匹配特定平台整型长度的类型    int和uint;可以跨平台的编程语言可以运行在多种平台上。平台的字节长度是有差异。64位平台现今已经较为普及,但8位、16位、32位的操作系统依旧存在。16位平台依然可以使用64位的变量,但运行性能和内存性能上较差。同理,在64位平台上大量使用8位、16位等与平台位数不等长的变量时,编译器也是尽量将内存对齐以获得最好的性能

     在使用int和uint类型时,不能假定它是32位或64位的整型,而是考虑int和uint可能在不同平台上的差异

2. 哪些情况使用int和uint

      逻辑对整型范围没有特殊需要,例如,对象的长度使用内建len()函数返回,这个长度可以根据平台根据不同平台的字节长度进行变化。实际用中,切片或map的元素数量等都可以用int来表示;反之,在二进制传输、读写文件的结构描述时,为保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用int和uint

浮点型

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

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

打印浮点数时,可以使用fmt包配合动“%f”,示例

package main

import (
	"fmt"
	"math"
)

//fmt 占位符
func main() {
	fmt.Printf("%f\n",math.Pi)
	fmt.Printf("%.2f\n",math.Pi)
}
// 执行
// PS D:\golang\goproject\src\lnhgo> go run day1\demo11\main.go
// 3.141593
// 3.14

  示例:输出正弦函数(Sin)图片

在go语言中,正弦函数由math包提供,函数入口为math.Sin。正弦函数的参数为float64,返回值也是float64.在使用正弦函数时,根据实际精度可以进行转换。Go语言的标准库支持对图片像素进行访问,并且支持输出各种图片,如JPEG、PNG、GIF等

1.设置图片背景色

    //图片大小
    const size = 300
    //根据给定大小创建灰度图
    pic := image.NewGray(image.Rect(0,0, size, size))
    // 遍历每个像素
    for x:=0;x<size;x++{
        for y:=0;y<size;y++{
            //填充为白色
            pic.SetGray(x,y,color.Gray{255})
        }
    }

 

灰度图是一种常见的图片格式,一般情况下颜色由8位组成,灰度范围为0~255,0表示黑色,255表示白色。初始化好的灰度图对象内存区域默认值都是0,对应全是黑色,考虑到显示效果和习惯,将所有像素设置255,也是白色

2.绘制正弦函数数轨迹

正弦函数是一个周期函数。定义域是实数集,值域范围是[-1,1]。用编程的通俗话:math.Sin函数的参数支持任意浮点数范围,函数返回值的范围总是在-1~1之间(两端);要将正弦函数放在图片上需要考虑一下一些因素

(1)math.Sin 的返回值在-1~1之间。需要考虑将正弦的输出幅度变大,可以将math.Sin的返回值乘以一个常量进行放大

(2)图片的坐标系原点在左上角,而math.Sin基于笛卡尔坐标系原点左下角,需要对图片进行上下翻转和平移。

将这些处理逻辑汇总

1     //从0到最大像素生成x坐标
2     for x:=0;x<size;x++{
3         //让sin的值的范围在0~2Pi之间
4         s:=float64(x)*2*math.Pi / size
5         //sin的幅度为一半的像素。向下偏移一半像素并翻转
6         y:=size/2-math.Sin(s)*size/2
7         //用黑色绘制sin轨迹
8         pic.SetGray(x,int(y),color.Gray{0})
9     }

 

 写入图片

1     //创建文件
2     file, err := os.Create("sin.png")
3     if err != nil{
4         log.Fatal(err)
5     }
6     // 使用png格式将数据写入文件
7     png.Encode(file,pic)
8     //关闭文件
9     file.Close()

 

布尔 型

   布尔型数据在Go语言中以bool类型进行声明,布尔型数据只有true(真)和false(假)两个值;Go语言中不允许将整型强制转换为布尔型

 1 package main
 2 
 3 import "fmt"
 4 
 5 //"fmt"
 6 //"string"
 7 //"strings"
 8 
 9 //fmt 占位符
10 func main() {
11     var n bool
12     fmt.Println(int(n)*2)
13 }
14 // PS D:\golang\goproject\src\lnhgo> go run day1\demo14\main.go
15 // # command-line-arguments
16 // day1\demo14\main.go:12:18: cannot convert n (variable of type bool) to type int

 

字符串

     字符串在Go语言中以原生数据类型出现。使用字符串就像使用其他原生数据类型(int、bool、float32、float64等)一样;字符串的值为双引号中内容,可以在go语言的源码中直接添加。 非ASCII 字符,代码

    str:= "hello world"
    ch:="你好"

 

1. 字符串转义符

      Go语言的字符串常见转义符包含回车、换行、单双引号制表符

 \r: 回车符(返回行首)

\n: 换行符(直接跳到下一行的痛列位置)

\t: 制表符

\`:单引号

\":双引号

\\:反斜杠

1 package main
2 import "fmt"
3 func main() {
4     fmt.Println("str:=\"c:\\Go\\bin\\go.exe\"")
5 }
6 // PS D:\golang\goproject\src\lnhgo> go run day1\demo14\main.go
7 // str:="c:\Go\bin\go.exe"

 

2. 字符串实现基于UTF-8编译

   Go语言里的字符串的内部实现使用UTF-8编译。通过rune类型,可以方便地对每个UTF-8字符进行访问。当然,Go语言也支持传统的ASCII码方式进行逐字符访问。

3. 定义多行字符串

    在源码中,将字符串的值以双引号书写的方式是字符串的常见表达方式,被称为字符串字面量(string literal)。这种双引号字面量不能跨行。如果需要在源码中嵌入一个多行字符时,就必须使用“`”字符

 1 package main
 2 import "fmt"
 3 func main() {
 4     //fmt.Println("str:=\"c:\\Go\\bin\\go.exe\"")
 5     const str = `第一行
 6     第二行
 7     第三行
 8     \r\n`
 9     fmt.Println(str)
10 }
11 // PS D:\golang\goproject\src\lnhgo> go run day1\demo14\main.go
12 // 第一行
13 //         第二行
14 //         第三行
15 //         \r\n

 

字符

    字符串中的每一个元素叫做“字符”。在遍历或者单个获取字符串元素时可以获得字符;Go语言的字符有以下两种:

(1)一种是uint8类型,或者叫byte型,代表了ASCII码的一个字符

(2)另一种是rune类型,代表一个UTF-8字符。但需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32

使用fmt.Printf中的“%T”动词可以输出变量的实际类型,使用这个方法可以查看byte和rune的本来类型

 1 package main
 2 import "fmt"
 3 func main() {
 4     var  a byte = 'a'
 5     fmt.Printf("%d %T\n",a,a)
 6     var b rune = ''
 7     fmt.Printf("%d %T\n",b,b)
 8 }
 9 // PS D:\golang\goproject\src\lnhgo> go run day1\demo14\main.go
10 // 97 uint8
11 // 20320 int32

      可以发现,byte类型的a变量,实际类型是uint8,其值为‘a’,对应的ASCII编码为97。

      rune类型的b变量的实际类型是int32,对应的Unicode码就是20320. Go使用了特殊的rune类型来处理Unicode,让基于Unicode的文本处理更为方便,也可以使用byte型进行默认字符串处理,性能和扩展性都有照顾。

UTF-8和Unicode有何区别?

Unicode 是字符集。ASCII也是一种字符集。

字符集为每个字符分配一个唯一的ID,使用到的所有字符在Unicode字符集中都有唯一的一个ID对应,例如上面例子中的a在Unicode与ASCII中的编码都是97。“你”在Unicode中的编码为20320,但是在不同国家的字符集中,“你”的ID不同。而无论任何情况下,Unicode中的字符的ID都是不会变化的。

UTF-8是编码规则,将Unicode中字符的ID以某种方式进行编码。UTF-8的是一种变长编码规则,从1到4个字节不等。编译规则如下:

(1)0xxxxxx 表示文字

(2)从128到0x10ffff表示其他字符

根据这个规则,拉丁文语系的字符编码一般情况下,每个字符依然占用一个字节,而中文每个字符占用3个字节。广义的Unicode指一个标准,定义字符集及编码规则,即Unicode字符集和UTF-8、UTF-16编码等。

切片 能动态分配的空间

    切片是一个拥有相同类型元素的可变长度的序列。切片的声明方式

var  name []T

     其中,T代码切片元素类型,可以是整型、浮点型、布尔型、切片、map、函数、数组

  切片的元素使用“[]”进行访问,在括号中提供切片的索引即可访问元素,索引的范围从0开始,且不超过切片的量大容量

 1 package main
 2 import "fmt"
 3 func main() {
 4     a := make([]int,3)
 5     a[0]=1
 6     a[1]=2
 7     a[2]=3
 8     fmt.Println(a)
 9 
10 }
11 // PS D:\golang\goproject\src\lnhgo> go run day1\demo14\main.go
12 // [1 2 3]

 

转换不同的数据类型

Go 语言使用类型前置加括号的方式进行类型转换,一般格式如下

T(表达式)

 

其中,T代表要转换的类型。表达式包括变量、复杂算子和函数返回值等。类型转换时,需要考虑两种类型的关系和范围,是否会发生数值截断

 1 package main
 2 import (
 3     "fmt"
 4     "math"
 5 )
 6 func main() {
 7     // 输出各数值范围
 8     fmt.Println("int8 range:",math.MinInt8,math.MaxInt8)
 9     fmt.Println("int16 range:",math.MinInt16,math.MaxInt16)
10     fmt.Println("int8 range:",math.MinInt32,math.MaxInt32)
11     fmt.Println("int8 range:",math.MinInt64,math.MaxInt64)
12 
13     //初始化一个32位整型值
14     var a int32 = 1047483647
15     //输出变量的十六进制形式和十进制值
16     fmt.Printf("int32:0x%x %d\n",a,a)
17     // 将a变量数值转换为十六进制,发生数值截断
18     b:=int16(a)
19     //输出变量的十六进制形式和十进制值
20     fmt.Printf("int16:0x%x %d\n",b,b)
21     //将常量保存为float32类型
22     var c float32 = math.Pi
23     //转换为int类型,浮点发生精度丢失
24     fmt.Println(c)
25     fmt.Println(int(c))
26 }
27 // 执行结果
28 // PS D:\golang\goproject\src\lnhgo> go run day1\demo15\main.go
29 // int8 range: -128 127
30 // int16 range: -32768 32767
31 // int8 range: -2147483648 2147483647
32 // int8 range: -9223372036854775808 9223372036854775807
33 // int32:0x3e6f54ff 1047483647
34 // int16:0x54ff 21759
35 // 3.1415927
36 // 3

 

指针

指针概念在Go语言中被拆分为两个概念

类型指针,允许对这个指针类型的数据进行修改。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算;切片,由指向起始元素的原始指针、元素数量、和容量组成

受益于这样的约束与拆分,Go语言的指针类型变量拥有指针的高效访问,但又不会发生指针偏移,从而避免非法修改关键性数据问题。同时,垃圾回收也比较容易对不会发生偏移的指针进行检索和回收。切片比原来指针具备更强大的特性,更安全,运行时会报出宕机,并打出堆栈,而原始指针只会崩溃;要明白指针需要知道几个概念:指针地址、指针类型、指针取值

认识指针地址和指针类型

每个变量在运行时都有一个地址,这个地址代表变量在内存中的位置。Go 语言中使用“&”操作符放在变量前面对变量进行取值操作

格式如下

ptr :=&v    //v的类型为T 

 

其中v 代表被取地址的变量,被取地址的v使用prt变量进行接收,prt的类型为“*T”,称作T的指针类型。“*”代表指针

实际用法

package main
import (
    "fmt"
    //"math"
)
func main() {
    var cat int =1
    var  str string = "banana"
    fmt.Printf("%p %p\n",&cat,&str)
}
// 执行结果
// PS D:\golang\goproject\src\lnhgo> go run day1\demo16\main.go
// 0xc00000a0b8 0xc000026070

 

   声明整型cat 变量;声明字符串str 变量;使用fmt.Printf的动词“%p” 输出cat和str变量取地址后的指针值,指针值带有“0x” 的十六进制前缀;输出的值每次运行是不同的,代表cat和str两个变量的地址。在32位平台上,将是32位地址;64位平台上是64位地址

    从指针获取指针指向的值

    在对普通变量使用“&”操作符获取地址获得的这个变量的指针后,可以使用“*”操作也就是指针取值

package main
import (
	"fmt"
	//"math"
)
func main() {
	var house = "Malibu Point 10880,90265"
	//对字符串取地址值,ptr类型为*string
	ptr := &house
	fmt.Printf("ptr type: %T\n",ptr)
	//打印ptr的指针地址
	fmt.Printf("address:%p\n",ptr)
	//对指针进行取值
	value := *ptr
	//查看取值后的类型
	fmt.Printf("value type: %T\n",value)
	//指针取值后就是指向变量的值
	fmt.Printf("value: %s\n",value)


}
// 执行结果
// PS D:\golang\goproject\src\lnhgo> go run day1\demo17\main.go
// ptr type: *string
// address:0xc000026070
// value type: string
// value: Malibu Point 10880,90265

  取地址操作符“&”和取值操作符“*”是一对互补操作符,“&”取出地址,“*”根据地址取出地址指向的值。变量、指针地址、指针变量、取地址、取值的互相关系和特性如下:

(1)对变量进行取地址(&)操作,可以获得这个变量的指针变量

(2)指针变量的值是指针地址

(3)对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值

使用指针修改值

通过指针不仅可以取值,也可以修改值

import (
	"fmt"
)
func swap (a,b *int){
	*a,*b=*b,*a
}
func main() {
    x, y:= 1,2
	fmt.Println(x,y)
	swap(&x,&y)
	fmt.Println(x,y)

}
// 执行结果
// PS D:\golang\goproject\src\lnhgo> go run day1\demo18\main.go
// 1 2
// 2 1

  使用指针获取变量命令行的输入信息

    Go语言的flag包中,定义的指令以指针类型返回。通过学习flag包,可以深入了解指针变量在设计上的方便之处。通过提前定义一些命令指令和对应变量,在运行时,输入对应参数的命令行参数后,经过flag包的解析后即可通过定义的变量获取命令行的数据

package main

import (
	"flag"
	"fmt"
)
//定义命令行参数
var mode = flag.String("mode","","process mode")
func main() {
	//解析命令行参数
	flag.Parse()
	//输出命令行参数
	fmt.Println(*mode)

}
// 执行结果
// PS D:\golang\goproject\src\lnhgo> go run day1\demo19\main.go --mode=fast
// fast

  创建指针的另一种方法new()函数

Go语言还提供了另一种方法来创建指针变量

new(类型)
一般这样写
str := new(string)
*str := "nin ja"
fmt.Prinlt(*str)

  new()函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向的值为默认值

 

 

 

 

 

 

 

 

 

 

     

 

posted @ 2026-05-26 09:00  烟雨楼台,行云流水  阅读(4)  评论(0)    收藏  举报