go语言的数据类型

值类型和引用类型

值类型

int、float、bool、string、数组、结构体
变量直接存储值,内存通常在栈中分配

引用类型

指针、slice切片、map、管道chan、interface
变量存储的是一个地址,这个地址对应的空间才是真正的存储数据(值),内存通常是在堆中分配的,没有任何变量引用这个地址时,改地址对应的数据空间就成为了一个垃圾,由GC来回收。

基本数据类型:

在Go中数据类型都有一个默认值,没有赋值时就会保留默认值,也叫零值。

数据类型默认值
整型0
浮点型0
字符型“”
布尔型false

数值型

Golang程序中整数类型变量在使用时,遵守保小不保大的原则,即在保证程序正确运行的情况下,尽量使用占用空间小的数据类型

整数类型:

类型占用空间备注
int32位系统4个字节 64位系统8个字节
uint32位系统4个字节 64位系统8个字节
rune和int32一样表示一个Unicode码
byte与uint8等价要储存字符时选用byte

有符号整数

类型占用空间表示范围
int81个字节-128 ~ 127
int162个字节-2^15 ~ 2^15-1
int324个字节-2^31 ~ 2^31-1
int648个字节-2^63 ~ 2^63 -1

无符号整数

类型占用空间表示范围
uint81个字节0~255
uint162个字节0~2^16 -1
uint324个字节0~2^31 -1
uint648个字节0~2^63 -1
package main

import (
	"fmt"
	"unsafe"
) 

func main(){
	var n int = 10
	//unsafe.Sizeof(n) 可以返回变量占用的字节数
	fmt.Printf("n 的类型 %T  n占用的字节数是%d",n, unsafe.Sizeof(n))
}

浮点类型:

可以用来表示小数
浮点数 = 符号位 + 指数位 + 尾数位
尾数位可能丢失造成精度损失

类型占用空间表示范围
float324个字节-3.403E38 ~ 3.403E38
float648个字节-1.798E308 ~ 1.798E308

字符型

没有专门的字符型,使用byte来保存单个字母字符,由字符组成
注意:不能用byte存汉字,在go中采用utf-8的编码,一个汉字会占3个字节,可以用int32或者rune来储存

package main

import (
	"fmt"
) 

func main(){
	//字符类型可以用来计算,相当于一个整数,数值为码值
	var n = 10 + 'a'
	fmt.Println(n)  //107
}

布尔型(bool)

只能取truefalse
占用一个字节
适用于逻辑运算


字符串(string)

是由固定长度的字符串联起来的字符序列,Go的字符是由单个字节连接起来的。Go语言的字符串的字节使用UTF-8编码标识Unicode文本。

使用形式:
1、双引号,会识别转义字符。
2、反引号,以字符串的原生形态输出保持换行和特殊字符,可以实现防止攻击。

注意:
1、字符串一旦赋值了,就不能修改了。
2、字符串拼接使用 +


基本类型的类型转换

基本语法 T 将值v的类型转换为T
注意:
1、被转换的是变量存储的数据,变量本身的数据类型没有变化。
2、在转换中,比如int64转成int8,编译时不会报错,只是转换的结果会按溢出处理,和我们希望的结果不一样。

package main

import (
	"fmt"
	"unsafe"
) 

func main(){
	var i int = 1
	var j float32 = float32(i)

	fmt.Printf("i 的类型 %T  n占用的字节数是%d \n" ,i, unsafe.Sizeof(i))
	fmt.Printf("j 的类型 %T  n占用的字节数是%d \n" ,j, unsafe.Sizeof(j))
}

在这里插入图片描述


派生/复杂数据类型:


指针(Pointer)

指针变量存的是一个地址,这个地址指向的内存空间才是值
值类型都有对应的指针类型,形式为 *指针类型
值类型包括:int 、float 、 bool、string、数组、结构体

package main

import (
	"fmt"
) 

func main(){
	var a int = 1
	fmt.Printf("a的地址%v\n",&a)
	var b *int = &a
	fmt.Printf("b的值%v\n",b)
	fmt.Printf("b的地址%v\n",&b)
	fmt.Printf("b指向的值%v\n",*b)
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/9ebd78926ca1480fbc9d6f893a4d5dac.png
利用指针改变值

package main

import (
	"fmt"
) 

func main(){
	var a int = 1

	var b *int = &a
	
	*b = 2

	fmt.Printf("a的值%v",a)
}

在这里插入图片描述


数组

基本用法

语法 var variable_name [SIZE] variable_type

package main

import (
	"fmt"
) 

func main(){
	arr := [6] int {1,2,3,4,5,6} //int 占8字节
	fmt.Printf("arr的地址是%p \n", &arr) 
	fmt.Printf("arr[0]的地址是%p \n", &arr[0]) //数组中第一个元素的地址和数组变量的地址是一样的
	fmt.Printf("arr[1]的地址是%p \n", &arr[1]) //后面元素的地址就是在数组地址基础上加上占用字节数

	// arr的地址是0xc00000a300 
	// arr[0]的地址是0xc00000a300 
	// arr[1]的地址是0xc00000a308
}

如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

var arr = [...]float32{1,2,3,4,5,6}

如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

arr := [5]float32{1:2.0,3:7.0}

注意事项

1、一旦声明,其长度就不能改变
2、数组创建后,如果没有赋值,有默认值(零值):
int–> 0
bool–>false
string–> “”
3、数组中的元素可以是任意类型


结构体(struct)


管道(Channel)


函数

为完成某一功能的程序指令(语句)的集合,称为函数。
函数执行时会在内存中开辟一个执行空间,函数执行完毕该空间释放。
在Go中,函数分为:自定义函数、系统函数。
Go函数支持多个返回值。

func 函数名(形参列表)(返回值类型列表){
	执行语句...
	return 返回值列表
}

函数的命名

1、函数的命名遵循标识符命名规格,首字母不能是数字
2、首字母大写的函数可以被本包和其他包文件使用,类似public
3、首字母小写只能被本包使用,其他包不能使用,类似于private
基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内部修改,不会影响到原来的值。
如果希望函数内的变量能影响到函数外的变量,可以传入变量的地址&,函数内衣指针的方式操作变量。

package main

import (
	"fmt"
) 

func test1( n int)  {
	n++
	fmt.Printf("test1 a= %v\n",n)
}

func test2( n *int )  {
	*n++
	fmt.Printf("test2 b=%v\n",*n)
}

func main(){

	a:=1
	b:= 1

	test1(a)
	test2(&b)

	fmt.Printf("a=%v\nb=%v\n",a,b)
}

在go中函数也是一种数据类型。

package main

import (
	"fmt"
) 

func getSum( n1 int, n2 int) int {
	return n1 + n2
}

//函数是一种数据类型,因此可以作为形参,并且调用
func sumFun(funvar func(int, int) int, num1 int, num2 int ) int {
	return funvar(num1,num2)
}

func main(){
  //可以复制给一个变量,该变量就是一个函数类型的变量了,通过该变量可以对函数调用。
	a:= getSum

	res1 := a(1,2)

	res2 := sumFun(a,3,4)

	fmt.Printf("res1 = %v \n res2 =%v \n",res1,res2)
}

在这里插入图片描述

支持返回值命名

package main

import (
	"fmt"
) 

func myfun(n1 int, n2 int) (sum int , sub int) {
	//sum,sub为默认返回值已声明,可以直接赋值
	sum = n1 + n2
	sub = n1 - n2
	return
}

func main(){
	
	a, b := myfun(20,10)
	c, _ := myfun(30, 40) // _代表占位符

	fmt.Printf("a = %v \nb =%v \nc =%v \n",a,b,c)
}

在这里插入图片描述

支持可变参数

通过args[index]获取参数

//支持0到多个参数
func myfun(args...int) int{}
//支持1到多个参数
func myfun(n int,args...int) int{}

匿名函数

1、在定义匿名函数时直接调用,这种方式匿名函数只能调用一次

func main(){
	res := func (n1 int,n2 int) int {
		return n1 + n2
	}(1,2)

	fmt.Println("a=",res)
}

2、将定义的匿名函数赋值给变量、这种方式可以多次调用

func main(){
	a := func (n1 int,n2 int) int {
		return n1 + n2
	}
	res := a(1,2)
	fmt.Println("res=",res)
}

闭包

闭包就是一个函数和其他相关的引用环境组合的一个整体

package main

import (
	"fmt"
) 

func add() func (int) int  {
	 n := 10
	return func (x int) int {
		return n + x
	}
}

func main(){
	f := add()
	res1 := f(2)
	res2 := f(3)
	fmt.Println("res=",res1,res2)
}

在这里插入图片描述

defer

特性

  1. 关键字 defer 用于注册延迟调用。
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
  3. 多个defer语句,按先进后出的方式执行。
  4. defer语句中的变量,在defer声明时就决定了。

用途

  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放

当go执行到defer时,不会立即执行defer后的语句,而是将defer后的语句亚茹到一个栈中,然后执行下一语句,在函数执行完之后,再从栈中执行语句(先入后执行)

package main

import (
	"fmt"
) 

func sum(n1 int, n2 int) int  {
	//defer入栈时会拷贝相应的值
	defer fmt.Println("n1=",n1)  //n1=10
	defer fmt.Println("n2=",n2)  //n2=20
	n1++
	n2++
	res := n1 + n2
	defer fmt.Println("res=",res) //res=32
	return res
}

func main(){
	num := sum(10,20)
	fmt.Println("num=",num)  //num=32
}

切片(slice)


接口(interface)


map


自定义数据类型

基本语法: type 自定义数据类型名 数据类型

package main

import (
	"fmt"
) 

func main(){
	//给int取了别名,在go中 myint 和 int 都是int类型,但是go认为他们是两个类型
	type myint int
	var num1 myint
	var num2 int
	num1 = 40
	num2 = num1 //cannot use num1 (type myint) as type int in assignment
	fmt.Printf("num1 = %v \num2 =%v \n",res1,res2)
}
type myFunType func(int,int) int

//函数是一种数据类型,因此可以作为形参,并且调用
func sumFun(funvar myFunType, num1 int, num2 int ) int {
	return funvar(num1,num2)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值