go的执行流程
- go源文件—>go build (编译)可执行的exe程序
–>运行
go编译运行的注意事项
- go build -o nimingmingde.exe source.go
- 如果程序有错,编译时,会在错我的哪行报错,,有助于调试错误
- go run source.go
go的语法要求和注意事项
- 严格区分大小写
- 不需要加分号
- 执行入口是main()函数
- 一行就写一条语句,一行一行编译
- 定义的变量或者import的包没有使用,代码就不能使用
- 大括号都是成对出现
go语言的转移字符
- 1)\t ;一个制表符,实现对齐功能 排版对齐
- 2)\n ; 换行符
- 3)" ;一个"
- 4)\r 回车
go 的注释
- 提高代码的阅读性
注释风格 - 行注释
- 块注释
go代码的格式化
go tab 缩进
使用命令行 cmd:> gofmt -w source.go
运算符两边各加一个空格
行长约定 建议超过80个字符换行
windows DOS disk operating system
- 查看当前目录dir
- 切换到当前目录 cd /d f:
- cd d:\test100
- 创建目录 md name
- 删除目录 rd namedirectory rd /q/s directoryname
- 新建或追加内容到文件 echo hello > d:\test100\abc.txt
- 复制或者移动 copy abc.txt d:\site\def.txt 剪切:move abc.txt f:\
- 删除文件 del abc.txt
- 清屏 cls
- 退出 exit
变量的注意事项
- 该区域的数据值可以在同一范围内(函数内)变化
- 变量在同一个作用域(在同一个函数或者在代码块)内不能重名(重新定义)
- 变量如果没有赋初值,int类型为0,strin类型为空字符串
- 变量:类型 名 值
- 变量的声明,初始化,赋值
GO的数据类型
一、基本数据类型
- 数值型(1.1整数类型[int,int8,int16,int64,uint,uint8,uint16,uint32,uint64,byte] 1.2浮点类型(float32,float64) )
- 字符型 :没有专门的字符型,使用byte来保存单个字母字符。
- 布尔型
- 字符串(string)
二、派生/复杂数据类型
5. 指针(pointer)
6. 数组
7. 结构体
8. 管道 (channel)
9. 函数
10. 切片
11. 接口
12. map
GO的整型
类型 | 有无符号 | 占用字节 | 范围 |
---|---|---|---|
int8 | 有符号 | 1字节 | -128-127 |
int16 | 有符号 | 2字节 | |
int32 | 有符号 | ||
int64 | 有符号 |
uint8 | 无符号 | 1字节 |
uint16 | 无符号 | 2字节 |
uint32 | 无符号 | 4 |
uint64 | 无符号 | 8 |
整数类型
类型 | 有无符号 | 存储空间 | 备注 |
---|---|---|---|
int | 有 | 32位系统4字节 64位系统8个字节 | |
uint | 无 | 32位系统4字节 64位系统8个字节 | |
rune | 有 | 与int32一样 | 等价int32,表示一个unicode码 |
byte | 无 | 与unit8等价 |
整数使用的细节
var n1 = 100
fmt.Printf("%T");//格式化输出
小数类型/浮点类型
小数类型就是用于存放小数,例如:1.2
小数类型分类
单精度float32 | 4字节 |
双精度float64 | 8字节 |
- 浮点数 = 符号位+指数位+尾数位
- 精度为题,精度丢失
- float64的精度比float32精度要准确
浮点数使用细节
- golang 浮点类型有固定的的范围和字段长度,不受OS的影响
- 默认为float64类型
没有专门的字符类型,如果存储单个字符(字母),使用byte存储
go的字符串不同,它是由字节组成的
如果我们保存的字符在ASCII表的,比如[0-1,a-z,A-Z]直接可以保存在byte
-
%v 表示按照变量的值输出
-
%d
-
%c
-
%f
-
%T 将变量的类型输出
-
golang数据类型不能自动转换 ,需要显示转换(强制转换)
-
go的基本的数据类型的转换
-
被转换的变量存储的数据(即值),变量本身的数据类型并没有变化
-
在转换中,比如将int64转成int8 [-128–127] 编译时不会报错,
知识转换的结果是按溢出处理,和我们希望的结果不一样。
如果没有使用一个包,但是又不想删除掉,前面加一个 _表示忽略
基本数据类型和string的转换
- 方一:fmt.sprintf()
- 方二:strconv 包函数
string类型转基本数据类型
函数itoa
go的指针(复杂类型)
- 基本的数据类型,变量存的就是值,也叫值类型。
- 获取变量的地址,用 &
- 指针类型,指针变量存的是一个地址,这个地址只想的空间存在的才是
指针细节说明
- 值类型,都有对应的指针类型,形式为 数据类型,比如int的对应的指针就是int,float32对应的指针类型就是*float,以此类推
- 值类型包括,基本数据类型 int系列,float系列,bool,string,数组和结构体struct
值类型和引用类型
常见的值类型和引用类型
- 值类型,基本数据类型 int系列、float系列、bool、string、数组、结构体struct。
- 引用类型:指针、切片、map、管道channel、interface等都是引用类型
值类型和引用类型的区别
- 值类型:变量直接存储,内存通常在栈中分配。
- 引用类型:变量的存储是一个地址,这个地址对应的空间才真正存储数据(值)
- 特殊的情况:编译逃逸分析
go 标识符命名规则
- 由26个英文字母大小写,0-9,_组成
- 数字不可以开头
- 严格区分大小写
- 标识符不能包含空格
- 下划线"_"本身在go中是一个特殊的标识符,称为空标识符。用于占用。
- 不能以系统保留关键字作为标识符(一共25个)
标识符命名规范
- 包名 保持package的名字和目录保持一致,尽量采取有意义的包名,
- 变量名、函数名、常量名:采用驼峰法
- 如果变量名 函数名常量名首字母大写,则可以被其他的包访问,如果首字母小写,则只能在
本包中使用。
go系统保留关键字25个 和 预定义标识符(36个)
go 运算符
- 1)算术运算符
- 2 )赋值运算符
- 3)比较运算符/关系运算符0
- 4)逻辑运算符
- 5)位运算符
- 6)其他运算符
取模运算
a%b = a - a / b * b
关系运算符,bool类型
- 关系运算符也叫比较运算符,if结构或者循环结构
逻辑运算符 && || !
- 用于连接多个条件,最终的结果也是一个bool值
短路与 因为第一个判断为false,后边的另一个判断就不执行了
短路或 因为第一个判断为true,后边的另一个判断就就不执行了
赋值运算符的分类
赋值运算符的左边只能是变量,右边可以使变量,表达式、常量值
表达式:任何有值都可以看做表达式
package main
import “fmt”
func main(){
//有两个变量,a和b,要求将其进行交换,但是不允许使用中间变量,最终打印结果
var a int = 10
var b int = 20
a = a + b
b = a - b
a = a - b
fmt.Printf(“a=%v b=%v”,a,b)
}
运算符优先级
只有单目运算符、赋值运算符是从右向左运算的
其他运算符从左向右
运算符的优先级
- 1后缀(括号()[]-> ++ --)
- 2单目运算符 + - !
- 3算数运算符
- 4移位运算符
- 5关系运算符
- 6位运算符
- 7逻辑运算符
- 8赋值运算符
- 9逗号(定义多个变量)
go的设计理念:一种事情有且只有一种方法完成
位运算符和移位运算符
go没有三元运算符,使用if …else 完成三元的运算
进制介绍
- 二进制 在go中不能直接使用二进制表示一个整数,沿用了C的特点。
- 十进制
- 八进制
- 十六进制
二进制转其他进制
二进制转八进制的方法 例如 11010101====》11->3 010->2 101->5
其他进制转二进制
八进制转成对应的二进制,需要将八进制的每一位,转成对应的一个3位的二进制数即可。
依据 8421
位运算
-
& 按位与 是双目运算符,其功能是参与运算的两数各对应的二进位相与。 运算规则:同时为1,结果为1,否则为0
-
| 按位或 是双目运算符,其功能是参与运算的两数各对应的二进位相或。 运算规则:有一个为1,结果为1,否则为0
-
^ 按位异或 是双目运算符,其功能是参与运算的两数各对应的二进位相异或。 运算规则:当二进位不同时,结果为1,否则为0
-
<< 左移运算符是双目运算符,其功能是把<<左边的运算数的各二进位全部左移若干位,高位丢弃,低位补0。左移n位就是乘以2的n次方。
-
》右移运算符 >>是双目运算符,其功能是把>>左边的运算数的各二进位全部右移若干位,右移n位就是除以2的n次方。
原码、反码、补码
对于有符号的数而言
- 1)二进制的最高位是符号位:0表示正数,1表示负数
- 2)正数的原码,反码,补码都一样
- 3)负数的反码=它的原码符号位不变,其他位取反(0->1,1->0)
1===>原码[0000 0001],反码[0000 0001],补码[0000 0001]
-1===>原码[1000 0001],反码[1111 1110],补码[1111 1111] - 4)负数的补码=它的反码+1
- 5)0的反码、补码都是0
- 6)在计算机运算的时候,都是以补码的方式来运算的。
- golang中只能独立使用,++和–只能独立使用
- golang中没有前 ++ 没有前–
循环嵌套层数的控制
- 嵌套分支不宜过多,建议控制在3层左右
switch
- case/switch后是一个表达式(常量值,变量 有一个返回值的函数 等都可以)
- case后边的表达式值的数据类型,必须和switch表达式数据类型一致。
- case后边可以带多个表达式,使用逗号间隔。
- case后边的表达式如果是常量值,则不能重复。
- default语句不是必须的
- case后可以直接声明/定义一个变量,分号结束,不推荐
- switch穿透falththrough,如果在case语句块后增加falthrough,则会继续执行下一个case也叫switch穿透。
- type switch 语句来判断interface变量中实际指向的变量类型
switch和if的比较
- 如果判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用switch语句,简洁高效。
- 其他情况,对区间判断和结果为bool类型的判断,使用if,if的使用范围更广。
for循环的使用细节
- 循环条件是返回一个布尔值的表达式
- for循环的第二种使用方式
j :=1
for j < 10{
fmt.Println(“呵呵呵”)
j++
} - for 循环的第三种使用方式
for{
}
- go提供了for-range的方式,可以方便遍历字符串和数组(数组的遍历)
- 如果我们的字符串含有中文,那么传统的遍历字符串的方式,就是错误,会出现乱码,原因是传统的对字符串的遍历是按照字节遍历的,而一个汉字在utf8对应的3个字节。
如何解决,需要将 str转成切片=》 - 对于for-range遍历方式而言,是按照字符方式遍历,因此如果有字符串是中文,也OK
while和do…while的实现
-
//循环变量初始化
for{
循环操作(语句)
循环变量迭代
if 循环条件表达式{
break//跳出for循环
}
} -
当循环条件成立后,就会执行break,break就是跳出for循环
多重循环控制
- 1)嵌套循环,外循环和内循环[建议一般使用两层,最多不要超过3层]
- 2)
编程问题解决
----先易后难,将一个复杂的问题分解成简单的问题
----先死后活,将一个变量先写死,后再写活
- break 语句出现在多层的语句块中,可以通过标签指明要终止的是那一层语句块。
- break默认会跳出最近的for循环
- break后边可以指定标签,跳出指定的标签
continue 跳转控制语句
- 1)continue语句用于结束本次循环,继续执行下一次循环。
- 2)continue语句出现在多层嵌套的循环语句中,可以通过标签指明要跳过的事那一层的循环,和break使用规则一样
goto语句
- go语言的goto语句可以无条件的转移到程序中指定的行
- goto语句通常与条件语句配合使用,可用来实现条件转移,跳出循环体等功能。
3.在go程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试都产生困难
基本语法:
goto label
…
label
return 使用在方法或者函数中,表示跳出所在的方法或者函数。
如果return是在main函数,表示终止程序。
函数
- 自定义函数
- 系统函数
包的引用和使用
包的本质就是一个文件夹,go是以包的形式来管理文件和项目目录结构的
包的作用
- 区分相同名字的函数、变量等标识符
- 当程序文件很多时,可以很好的管理项目
- 控制函数、变量等访问范围,即作用域
包的相关说明
打包的基本语法
package 包名
引入包的基本语法
import "包的路径”
包使用细节的说明
- 在给一个文件打包时,该包对应一个文件夹,比如这里的utils文件夹对应的包名就是utils,
文件的包名通常和文件所在的文件夹名一致,一般为小写字母 - 当一个文件要使用其他包函数或变量时,需要先引入对应的包
1)引入方式:import “包名”
- 引入方式2 :
import(
“包名”
“包名”
)
- package指令在文件第一行,然后是import指令
- 在import包时,路径从$GOPATH的src下开始,不用带src,编译器会自动从src下开始引入
- 为了让其他包的文件,可以访问到本包的函数,则该函数名的首字母需要大写。类似其他语言的public,这样才能挎包访问,
- 在访问其他包函数时,其语法是包名.函数名。
- 如果包名较长,go支持给包取别名,取别名后原来的包名就不能使用了。
- 如果你要编译成一个可执行文件,就需要将这个包声明为main,即package main,这个就是一个语法规范,如果你是写一个库,包名可以自定义。
go 函数调用机制底层剖析
通俗易懂的方式理解
栈区(基本数据类型一般分配到栈区)
一般来说,可能存在逃逸分析
堆区 引用数据类型一般分配到堆区,
代码区(代码存放到这)
函数注意事项和细节讨论
- 函数的形参列表可以是多个,返回值列表也可以是多个
- 形参列表和返回值列表的数据类型可以是值类型和引用类型
- 函数的命名遵循标识符命名规范,首字母不能是数字,首字
母大写该函数可以被本包文件和其他包文件使用,类似public,
首字母小写,只能被本包文件使用,其他包文件不能使用,类似private - 函数中的变量时局部的,函数外不生效
- 基本数据类型和数组默认都是值传递,即进行指拷贝。
在函数内修改,不会影响到原来的值。 - 如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,
函数内以指针的方式操作变量。从效果上看类似引用 - go函数不支持重载
map 切片 空接口的方式达到重载
函数注意事项
8. 在go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用
9. 函数既然是一种数据类型,因此在go中,函数可以作为形参,并且调用。
10. 为了简化数据类型定义,go支持自定义数据类型。
基本语法:type 自定义数据类型名, 数据类型 //理解:相当于一个别名
11. 支持对函数返回值命名
12. 使用_标识符,进行占位符
13. go中支持多边参数
说明:args 是slice切片,通过args[index]可以访问各个值。
init函数
每一个源文件都可以包含一个init函数,
如果一个文件同事包含全局变量定义,init函数和main函数,则执行的流程是变量定义->init函数->main函数
int函数最主要的作用,就是完成初始化工作
当执行到defer时,暂时不执行,会将defer后边的语句压入到独立的栈中(defer栈)
当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行。
在defer将语句放入栈时,也会将相关的值拷贝同时入栈。
defer最主要的价值在于,当函数执行完毕后,可以及时的释放函数创建的资源。
在golang编程中的通常做法是,创建资源后,比如(打开文件,获取了数据库的连接,或者是锁资源)可以执行defer file.close()
在defer后,可以继续使用创建资源
当函数完毕后,系统会一次从defer栈中,取出语句,关闭资源。
这种机制,非常简洁,不在为关闭资源所烦恼。
两种传递方式
- 值传递
- 引用传递
地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。
值传递:基本数据类型 int float类型,bool string 数组和结构体struct
引用传递:指针 slice切片 map 管道chan interface等都是引用类型
值传递和引用传递使用特点
- 1)值类型默认都是值传递,变量直接存储值,内存通常在栈中分配。
- 2)引用类型默认是引用传递,变量存储的是一个地址,这个地址对应的空间才真正存储数据值。
- 3)如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量,从效果上看类似引用。
变量作用域
4. 函数内部声明/定义的变量叫局部变量,作用域仅限于函数内部。
5. 函数外部声明的变量叫全局变量,作用域在整个包都有效,如果其首字母大写,则作用域在整个程序有效。
6. 如果变量是在一个代码块中,比如for/if,那么这个变量的作用域就在该代码块。
go中常用的系统函数
- 通知字符串长度,按字节len(str)
- 字符串遍历,同时处理有中文的问题。[]rune()转成切片
- 字符串转整数,strconv.Atoi()
- strconv.IToa() 整数转字符串
- 字符串转 []byte 切片 var bytes = []byte(“hello go”)
- []byte 转字符串, str = string([]byte{97,98,99});
- 10进值转2,8,16进制,str = strconv.FormatInt()
- 查找子串中是否在指定的字符串中 strings.Contains()
- 统计一个字符串有几个指定的子串,strings.Count()
- 不区分大小写的字符串比较(==是区分大小写)strings.EqualFold()
- 回子串在字符串第一次出现的index值,如果没有返回-1,strings.Index()
- 返回子串在字符串最后一次出现的位置,如果没有返回-1 strings.LastIndex()
- 将制定的子串替换成另外一个子串,strings.Replace()
- 按照指定的某个字符,为分割标识,讲一个字符串拆分成字符串数组:strings.Split()\
- 将字符串的字母进行大小写的转换 strings.ToLower() strings.ToUpper()
- 将字符串左右两边的空格去掉,strings.TrimSpace()
- 将字符串左右两边指定的字符去掉 strings.Trim() 原来字符串没有变化
- 将字符串左边指定的字符去掉 strings.TrimLeft();
- 将字符串右边指定的字符去掉
- 判断字符串是否以指定的字符串开头 strings.HasPrefix()
- 判断字符串是否已指定的字符串结束 strings.HasSuffix()