2-Golang变量
变量的使用步骤
- 声明变量
- 给变量赋值
- 使用变量
package main
import "fmt"
func main() {
// 声明变量
var i int
// 给变量赋值
i = 10
// 使用变量
fmt.Println("i=", i)
}
Golang变量使用的三种方式
- 第一种:指定变量类型,声明后若不赋值,使用默认值
- 第二种:根据值自行判定变量类型(类型推导)
- 第三种:省略var,注意:=左侧的变量不应该是已经声明过的,否则会导致编译错误
func var3declare() {
// 第一种
var i int
fmt.Println("i=", i)
// 第二种
var num = 10.11
fmt.Println("num=", num)
// 第三种
name := "tom"
fmt.Println("name=", name)
}
Golang变量其它特点
- 在编程中,有时我们需要一次性声明多个变量,Golang也提供这样的语法
- 如何一次性声明多个全局变量:在go中函数外部定义的变量就是全局变量
n1, name, n3 := 100, "tom", 888
- 变量在声明的区域内数据值可以在同一类型范围内不断变化
- 变量在同一个作用域(在一个函数或者代码块)内不能重名
- 变量=变量名+值+数据类型,变量三要素
- Golang的变量如果没有赋初值,编译器会试用默认值,比如int默认值是0,string默认值是空串,小数默认值是0
程序中+号的使用
- 当左右两边都是数值类型时,则做加法运算
- 当左右两边都是字符串,则做字符串拼接
func plusSymbol() {
var i = 1
var j = 2
var r = i + j
fmt.Println("r=", r)
str1 := "hello "
str2 := "world"
str3 := str1 + str2
fmt.Println("str3=", str3)
}
Golang数据类型基本介绍
整数类型
-
Golang各整数类型分有符号和无符号,int、uint的大小和系统有关
-
Golang的整型默认声明为int型
-
如何在程序中查看某个变量的字节大小和数据类型:
unsafe.Sizeof(x)
-
Golang程序中整型变量在使用时,遵守保小不保大原则,即:在保证程序正确运行下,尽量使用占用空间小的数据类型
-
bit:计算机中最小的存储单位,byte:计算机中基本存储单元;1byte=8bit
func testInt() {
var i = 1
fmt.Printf("i的数据类型维:%T\n", i)
fmt.Printf("i占用的字节数为:%d", unsafe.Sizeof(i))
var s = "你好"
fmt.Println(utf8.RuneCountInString(s))
/*
unsafe.Sizeof返回的是数据类型的大小,而string在Go中并不是直存类型,它是一个结构体类型
type StringHeader struct {
Data uintptr
Len int
}
在64位系统上uintptr和int都是8字节,加起来就16了,结果16
*/
fmt.Printf("s的数据类型:%T, 占用的字节数:%d\n", s, unsafe.Sizeof(s))
// Golang默认编码utf-8,中文在utf-8编码下占用3个字节,结果6
fmt.Println("s的长度为:", len(s))
// byte等同于int8,用来处理ASCII字符;rune等同于int32,用来处理Unicode或utf-8字符,结果2
fmt.Println("s的长度为:", len([]rune(s)))
}
小数类型/浮点型
- 关于浮点数在机器中存放形式的简单说明,浮点数=符号位+指数位+尾数位,浮点数都是有符号的,尾数部分可能丢失,造成精度损失,如果保存一个精度高的数,应该选用float64
- Golang浮点类型有固定的范围和字段长度,不受具体OS的影响
- Golang的浮点型默认声明为float64类型
- 浮点型常量有两种表示形式:
5.12
,.512
,5.12e2
,5.12E-2
func testFloat() {
num1 := 5.12
num2 := .512
num3 := 5.12e2
num4 := 5.12E2
num5 := 5.12E-2
num6 := 5.12e-2
fmt.Println(num1, num2, num3, num4, num5, num6)
}
字符类型
- Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存
- 字符串就是一串固定长度的字符连接起来的字符序列。Go的字符串是由单个字节连接起来的,也就是与传统的字符串是由字符组成的不同,Go的字符串由字节组成
- 如果我们保存的字符在ASCII表的,如[0-1,a-z,A-Z...]直接可以保存到byte
- 如果我们保存的字符对应码值大于255,这时我们可以考虑使用int类型保存
- 如果我们需要按照字符的方式输出,这时我们需要格式化输出,即
fmt.Printf("%c", c)
- 字符常量是用单引号括起来的字符,例如:
var c1 byte = 'a'
,va c2 int = '中'
- Go中允许使用转义字符
\
将其后的字符转变为特殊字符型常量 - Go语言的字符使用utf-8编码,英文字母-1个字节,汉字-3个字节
- 在Go中,字符的本质是一个整数,直接输出时,是该字符对应的utf-8编码的码值
- 可以直接给某个变量赋值一个数字,然后按格式化输出
%c
,会输出该数字对应的Unicode字符 - 字符类型是可以进行运算的,相当于一个整数,因为它都对应由Unicode码
- 字符型存储:字符>>对应码值>>二进制>>存储;字符型读取:二进制>>码值>>字符>>读取
func testChar() {
var c1 byte = 'a'
var c2 byte = '0'
fmt.Println("c1=", c1)
fmt.Println("c2=", c2)
fmt.Printf("c1=%c, c2=%c\n", c1, c2)
var c3 rune = '北'
fmt.Printf("c3=%c,c3对应的码值=%d\n", c3, c3)
}
/*
c1= 97
c2= 48
c1=a, c2=0
c3=北,c3对应的码值=21271
*/
布尔类型
- 布尔类型也叫bool类型,bool类型数据只允许取值true和false
- bool类型占用1个字节
- bool类型适用于逻辑运算,一般用于程序流程控制
func testBool() {
var b = false
fmt.Println("b=", b)
fmt.Println("b的占用空间=", unsafe.Sizeof(b))
}
string类型
- 字符串就是一串固定长度的字符连接起来的字符序列,Go的字符串是由单个字节连接起来的,Go语言的字符串的字节使用utf-8编码标识的Unicode文本
- Go语言的字符串的字节使用utf-8编码标识的Unicode文本,这样Golang统一使用utf-8编码,中文乱码问题不再会困扰程序员
- 字符串一旦赋值了,字符串就不能修改了:在Go中,字符串是不可变的
- 字符串的两种表现形式:双引号,会识别转义字符;反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果
- 当一行字符串太长时,需要使用到多行字符串,可以分行写,但是注意,需要将+保留在上一行
func testString() {
var str string = "hello world"
fmt.Println("str=", str)
str2 := "hello" + "hello" +
"world" + "world"
fmt.Println("str2=", str2)
}
基本数据类型的默认值及相互转换
- Golang和Java/C不同,Go在不同类型的变量之间赋值时需要显示转换。也就是说Golang中数据类型不能自动转换
- 表达式
T(v)
将值v转换为类型T - Go中,数据类型的转换可以是从范围小>>范围大,也可以是范围大>>范围小
- 被转换的是变量存储的数据(即值),变量本身的数据类型并没有变化
- 在转换中,比如将int64转换成int8,编译时不会报错,只是转换的结果按溢出处理,和我们希望的结果不一样,因此在转换时,需要考虑范围
func testChange() {
var i int32 = 100
var n1 float32 = float32(i)
var n2 int8 = int8(i)
var n3 int64 = int64(i)
// %v相应值的默认格式
fmt.Printf("i=%v n1=%v n2=%v n3=%v\n", i, n1, n2, n3)
fmt.Printf("i type is %T\n", i)
}
基本数据类型和string的转换
- 基本数据类型>>string:
fmt.Sprintf("参数", 表达式)
,Sprintf根据format参数生成格式化的字符串并返回该字符串 - 基本数据类型>>string:使用strconv包的函数
- string>>基本数据类型:使用strconv包的函数
- 将string类型转换成基本数据类型时,要确保string类型能转换成有效的数据,比如我们可以把"123"转换成一个整数,但是不能把"hello"转换成一个整数,如果这样做,Golang直接将其转换成0,其他类型也是一样的道理:float>>0,bool>>false
func testChangeString() {
var num1 int = 99
var num2 float64 = 23.456
var b bool = true
var myChar byte = 'h'
var str string
// Sprintf根据format参数生成格式化的字符串并返回该字符串
str = fmt.Sprintf("%d", num1)
fmt.Printf("str type %T str=%q\n", str, str)
str = fmt.Sprintf("%f", num2)
fmt.Printf("str type %T str=%q\n", str, str)
str = fmt.Sprintf("%t", b)
fmt.Printf("str type %T str=%q\n", str, str)
str = fmt.Sprintf("%c", myChar)
fmt.Printf("str type %T str=%q\n", str, str)
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
var num7 int = 99
var num8 float64 = 23.45645233431232
var b2 bool = true
// 转换为10进制>>string
str = strconv.FormatInt(int64(num7), 10)
fmt.Printf("str type %T str=%q\n", str, str)
/*
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。
fmt表示格式:'f'(-ddd.dddd)、'b'(-ddddp±ddd,指数为二进制)、'e'(-d.dddde±dd,十进制指数)、
'E'(-d.ddddE±dd,十进制指数)、'g'(指数很大时用'e'格式,否则'f'格式)、
'G'(指数很大时用'E'格式,否则'f'格式)。
prec控制精度(排除指数部分):对'f'、'e'、'E',它表示小数点后的数字个数;对'g'、'G',
它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
*/
str = strconv.FormatFloat(num8, 'f', 10, 64)
fmt.Printf("str type %T str=%q\n", str, str)
str = strconv.FormatBool(b2)
fmt.Printf("str type %T str=%q\n", str, str)
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
var str3 string = "true"
var b3 bool
// 第一个返回值保存转换后的值,第二个返回值判断是否转换成功。
b3, _ = strconv.ParseBool(str3)
fmt.Printf("b type %T b=%v\n", b3, b3)
var str2 string = "1234556"
var n1 int64
var n2 int
n1, _ = strconv.ParseInt(str2, 10, 64)
n2 = int(n1)
fmt.Printf("n1 type %T n1=%v\n", n1, n1)
fmt.Printf("n2 type %T n2=%v\n", n2, n2)
var str4 string = "1234.345"
var f1 float64
f1, _ = strconv.ParseFloat(str4, 64)
fmt.Printf("f1 type %T f1=%v\n", f1, f1)
}
指针
- 基本数据类型,变量存的就是值,也叫值类型
- 获取变量的地址,用&,比如:
var num int
,获取num的地址:&num
- 指针类型,指针变量存的是一个地址,这个地址指向的空间才是值
- 获取指针类型所指向的值,使用:*,比如:
var ptr *int
,使用*ptr
获取ptr指向的值 - 值类型,都有对应的指针类型,形式为
*数据类型
,比如int的对应的指针就是*int
,float32对应的指针类型就是*float3
,以此类推 - 值类型包括:基本数据类型int系列,float系列,bool,string,数组和结构体struct
func testPointer() {
var i int = 10
fmt.Println("i的地址=", &i)
// ptr是一个指针变量,ptr的类型是*int,ptr本身的值是&i
var ptr *int = &i
fmt.Printf("ptr=%v\n", ptr)
fmt.Printf("prt的地址=%v\n", &ptr)
// 使用*ptr获取ptr指向的值
fmt.Printf("ptr指向的值=%v\n", *ptr)
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
var num int = 9
fmt.Printf("num address=%v\n", &num)
var ptr2 *int
// ptr2存num的地址,该地址指向9
ptr2 = &num
// 修改ptr2指向的值
*ptr2 = 10
fmt.Printf("num=%v\n", num)
}
值类型和引用类型
- 值类型包括:基本数据类型int系列,float系列,bool,string,数组和结构体struct;变量直接存储值,内存通常在栈中分配
- 引用类型:指针、slice切片、map、管道channel、interface等都是引用类型;变量存储的是一个地址,这个地址对应的空间才真正存储数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收
标识符的命名规范
- golang对各种变量、方法、函数等命名时使用的字符序列称为标识符,凡是自己可以起名字的地方都叫标识符
- 标识符由26个英文字母大小写,0-9,_组成,数字不可以开头,Golang中严格区分大小写,标识符不能含空格
- 下划线_本身在Go中是一个特殊的标识符,称为空标识符。可以代表任何其他的标识符,但是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能作为标识符使用
- 不能以系统保留关键字作为标识符(一共25个)
- 包名:保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,不要和标准库冲突
- 变量名、函数名、常量名:采用驼峰法
- 如果变量名、函数名、常量名首字母大写,则可以被其他的包访问;如果首字母小写,则只能在本包中使用(注:可以简单的理解成,首字母大写是公开的,首字母小写则是私有的),在Golang中没有public,private等关键字
- 系统保留关键字
- 系统的预定义标识符
- GOPATH下的src默认帮忙添加,因此引入自定义包,只需从src的下一级目录开始即可