语法要求:严格区分大小写;一行一行编译,一行只写一条语句;go语言定义的变量或者import的包如果没有使用,代码不能编译通过
转义字符的使用:回车\r 从当前行的最前面开始输出,覆盖掉以前的内容
#编译并生成可执行文件
go build 文件名.go
#编译生成可执行程序并运行
go run 源码文件.go
go env 查看环境信息
go text
go语言自带测试工具,会自动读取源码目录下面名为*_test.go的文件,生成并运行测试用的可执行文件
常用命令行
go语言关键字以及使用方式
1命名规则
数字不能开头
区分大小写
允许使用字母数字下划线
不允许使用关键字
见名知意
2基本数据类型
派生数据类型
指针,数组,结构体,通道,切片,函数,接口,map
基本数据类型
布尔,数值,字符串
驼峰式命名:
小驼峰如myName可以在包内部使用,大驼峰如MyName可以被外部函数使用
ASCII码:0-31控制字符 使用转义字符表示内容,32-126 默认字符
127 del 字符
一个中文汉字占三个字符
3类型转换
package main
import "fmt"
func main() {
//去市场买菜
price := 3.25
weight := 5
//fmt.Printf("%T\n", price)
//fmt.Printf("%T\n", weight)
//sum := price * float64(weight)
// 浮点型转整型,会丢失精度
sum := int(price * float64(weight))
fmt.Println(sum)
}
func main() {
// type tune = int32 两个数据类型可以计算
ch := 'A' //rune == int32
var b int32 = 100
fmt.Println(ch+b)
}
4派生数据类型
数组
一组具有相同数据类型在内存中有序储存的数据集合
数组的长度在定义后不可以修改
func main() {
// type tune = int32 两个数据类型可以计算
//ch := 'A' //rune == int32
//var b int32 = 100
//fmt.Println(ch+b)
//var arr []int 默认值为0
//使用数组名+下标进行数组初始化 下标是从0开始的到数组最大元素个数-1
//var arr [10]int
//arr[0] = 123
arr := [10]int{1,2,3,4,5,6,7,8,9,10}
//fmt.Println(len(arr))
//遍历数组元素
//for i := 0;i < len(arr);i++{
// fmt.Println(arr[i])
//}
for i, j := range arr{
fmt.Println(i, j)
}
}
运行结果如下
如果不赋值的话,默认值为0
数组内存存储
func main() {
arr := [10]int{1,2,3,4,5,6,7,8,9,10}
for i := 0;i < len(arr);i++{
//&取地址运算符
fmt.Println(&arr[i])
}
}
切片
一组具有相同数据类型在内存中有序储存的可扩容的数据集合
func main4() {
//切片的定义和使用
//var 切片名 []数据类型
//var slice []int
//var slice []int = make([]int, 10)
//slice[0]=123
var slice []int
fmt.Println(len(slice)) //计算长度
fmt.Println(cap(slice)) //计算容量
//使用append对切片进行扩容
slice = append(slice, 1,2,3,4,5)
fmt.Println(len(slice))
fmt.Println(cap(slice))
fmt.Println(slice)
}
切片的截取
//func main5() {
// //切片的截取
// slice := []int{1,2,3,4,5,6,7,8,9,10}
// //左闭右开 包含起始下标 不包含结束下标
// //s := slice[2:7]
// //s := slice[:5]
// s := slice[2:5:6] //实际容量=容量-起始下标
// s[0] = 333
// //切片的截取 是将新的切片指向原切片的内存地址 修改一个会影响另一个
// fmt.Println(s)
// fmt.Println(slice)
//}
切片的拷贝
func main() {
slice := []int{1,2,3,4,5}
//s := slice
//s[2] = 33
//在储存两个内容完全相同 改变一个值不会相互影响
s := make([]int, 5)
copy(s, slice)
s[2] = 33
fmt.Println(s)
fmt.Println(slice)
}
map
//func main7() {
// //map的定义
// //var 字典名 map[键类型]值类型
// //var m map[int]string = make(map[int]string, 10)
// //m[1001] = "键盘"
// //m[8888] = "鼠标"
// //map是无序的集合
// m := map[int]string{1:"dfg", 2:"freg"}
// for k, v := range m{
// fmt.Println(k, v)
// }
//}
func main() {
m := make(map[int]string)
m[1] = "sdgf"
m[2] = "trhh"
if v, ok := m[1];ok{
fmt.Println(v)
}else{
fmt.Println("不存在")
}
delete(m, 1)
fmt.Println(len(m))
fmt.Println(m)
}
new和make的区别:
两者都是用来做内存分配的
make只用于slice,map 以及channel的初始化,返回的还是这三个引用类本身
而new
用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针
指针
go语言中函数传参都是值拷贝,记住两个符号:&(取地址)和*(根据地址取值)
//func main9() {
// a := 10
// //取出变量a所在内存的地址
// var p *int = &a
// fmt.Println(p)
// fmt.Println(&a)
// //通过指针间接修改变量的值
// *p = 123
// fmt.Println(p)
//}
func main() {
//error
//定义指针 默认值为nil 指向内存地址编号为0的空间 内存地址0-255为系统占用 不允许用户读写操作
//var p *int
//*p = 123
//fmt.Println(*p)
//开辟数据类型大小的空间 返回值为指针类型
//new(数据类型)
var p *int
p = new(int)
*p = 123
fmt.Println(*p)
}
if语句
//if 表达式{} 如果表达式为真 执行{}的代码
// //if 表达式{代码1} else{代码2} 如果表达式为真,执行代码1
//
// //score := 0
// //fmt.Scan(&score) //阻塞式请求
// //if score > 700{
// // fmt.Println("我问问")
// //}else if score > 600{
// // fmt.Println("而政府")
// //}else{
// // fmt.Println("梵蒂冈")
// //}
switch语句
// //day := 0
// //var m int
// //fmt.Scan(&m)
// //switch m {
// //case 1, 3, 5, 7, 8, 10, 12:
// // day = 31
// // //fallthrough //执行完当前分支 继续向下执行
// //case 2:
// // day = 29
// //}
// //fmt.Println(day)
// //浮点型因为精度问题可能在switch中认为是同一个值
// //pi := 3.14
// //switch pi{
// //case 3.14:
// // fmt.Println(pi)
// //case 3:
// // fmt.Println(pi)
// //}
// //score := 0
// //fmt.Scan(&score)
// //switch {
// //case score > 700:
// // fmt.Println("df")
// //case score > 600:
// // fmt.Println("fs")
// //default:
// // fmt.Println("cds")
// //}
for语句
func main() {
/*
for 表达式1:表达式2:表达式3{
代码体
}
for 表达式{
代码体
}
for range 集合{
代码体
}
*/
//sum := 0
//for i := 1;i <= 100; i++{
// sum += i
//}
//fmt.Println(sum)
//嵌套循环
//for i := 1;i<=5;i++{
// for j := 1;j<=5;j++{
// fmt.Println(i,j)
// }
//}
//冒泡排序
slice := []int{6, 4, 8, 3, 5}
for i := 0;i
跳出语句
break语句:在循环语句中使用break跳出语句
continue语句:在循环语句中,如果希望立即终止本次循环,并执行下一次循环,就需要用到continue
函数定义
func 函数名(参数)(返回值){
函数体
}
//func sayHello(){
// //定义不需要string类型的name参数
// fmt.Println("hello")
//}
//func sayHello2(name string){
// fmt.Println("hello", name)
//}
//go语言中没有默认参数
//可变参数与不可变参数放在一起时,可变参数放在最后
func intSum(a int, b int) int {
sum := a+b
return sum
}
//也可以定义多返回值
func calc(a, int b) (sum, sub int){
sum = a + b
sub = a - b
return
}
func main() {
x, y := calc(100, 200)
fmt.Println(x, y)
// fmt.Println(intSum(2,3))
}
defer语句
先被defer的语句最后执行,最后被defer的语句最先被执行
func main() {
//defer:延迟执行
fmt.Println("start...")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
//fmt.Println(intSum(2,3))
}
函数进阶
var num = 10
func testGlobal(){
num := 100
name := "wowowo"
//可以在函数中使用变量
//先在自己函数中查找,找到了就用自己函数中的
//函数中找不到变量就往外层找
fmt.Println("数字是:", num)
fmt.Println(name)
}
func main() {
testGlobal()
}
闭包和匿名函数
//匿名函数和闭包
//定义一个函数它的返回值是一个函数
//把函数作为返回值
func a(name string) func(){
//name := "fdsf"
return func() {
fmt.Println("hello", name)
}
}
func main() {
//闭包=函数+外层变量的引用
r := a("jncxu") //r是一个闭包
r()//相当于执行了a函数内部的匿名函数
}
panic和recover
go语言中没有异常机制,但是使用panic和recover模式处理机制错误。panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func a(){
fmt.Println("func")
}
func b(){
defer func() {
err := recover()
if err != nil{
fmt.Println("func b error")
}
}()
panic("panic in b")
}
func main() {
a()
b()
}
运行结果
GOROOT=G:\golang_env #gosetup
GOPATH=D:\work\goCode #gosetup
G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup
C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup
func
func b error
Process finished with exit code 0
类型别名和自定义类型
自定义类型 可以使用type关键字来自定义类型
type MyInt int
类型别名 规定:TypeAlias只是Type的别名,就像一个人有小名,大名,英文名但所有名字都是一个人
type TypeAlias = Type
类型定义和类型别名的区别
type MyInt int
type MiInt = int
func main() {
var i MyInt
var j MiInt
fmt.Printf("type of i:%T\n", i)
fmt.Printf("type of j:%T\n", j)
}
输出
GOROOT=G:\golang_env #gosetup
GOPATH=D:\work\goCode #gosetup
G:\golang_env\bin\go.exe build -o C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe D:\work\goCode\src\studyGo\two.go #gosetup
C:\Users\PC\AppData\Local\Temp\___go_build_two_go.exe #gosetup
type of i:main.MyInt
type of j:int
Process finished with exit code 0
结构体定义与实例化
定义 go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这 种数据类型叫做结构体(struct) t 通过struct来实现面向对象
使用type和struct关键字来定义结构体
//定义结构体
type person struct {
name, city string
age int8
}
实例化
type person struct {
name, city string
age int8
}
func main() {
var p person
p.name = "fncsdjf"
p.age = 19
p.city = "fds"
fmt.Printf("p=%#v\n", p)
fmt.Println(p.name)
}
匿名结构体
func main() {
var user struct{
name string
married bool
}
user.name = "fdsf"
user.married = false
}
结构体的初始化
键值对初始化
值的列表进行初始化
func main() {
//键值对初始化
//a := &person{
// name: "你你你",
// city: "背景",
// age: 19,
//}
//fmt.Printf("%#v\n", a)
//值的列表进行初始化
b := &person{
"我问问",
"背景",
19,
}
fmt.Printf("%#v\n", b)
}
注意
必须初始化结构体的所有字段
初始值的填充顺序必须与字段在结构体中的声明顺序一致
该方式不能和键值初始化方式混用
构造函数
type person struct {
name, city string
age int8
}
//构造函数
func newPerson(name, city string, age int8) *person{
return &person{
name: name,
city: city,
age: age,
}
}
func main() {
c := newPerson("gfbb", "vcv", int8(19))
fmt.Printf("type:%T value:%#v\n", c, c)
}