20个小时快速入门GO语言学习笔记:https://www.bilibili.com/video/av20432910?p=6
2009年11月10日,Go语言正式成为开源编程语言家庭的一员。
Go语言(或称Golang)是云计算时代的C语言。Go语言的诞生是为了让程序员有更高的生产效率,Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。开发人员在为项目选择语言时,不得不在快速开发和性能之间做出选择。C和C++这类语言提供了很快的执行速度,而 Ruby 和 Python 这类语言则擅长快速开发。Go语言在这两者间架起了桥梁,不仅提供了高性能的语言,同时也让开发更快速。
可直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去就完成了。
静态类型语言,但是有动态语言的感觉,静态类型的语言就是可以在编译的时候检查出来隐藏的大多数问题,动态语言的感觉就是有很多的包可以使用,写起来的效率很高。
语言层面支持并发,这个就是Go最大的特色,天生的支持并发。Go就是基因里面支持的并发,可以充分的利用多核,很容易的使用并发。
内置runtime,支持垃圾回收,这属于动态语言的特性之一吧,虽然目前来说GC不算完美,但是足以应付我们所能遇到的大多数情况,特别是Go1.1之后的GC。
简单易学,Go语言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go关键字是25个,但是表达能力很强大,几乎支持大多数你在其他语言见过的特性:继承、重载、对象等。
丰富的标准库,Go目前已经内置了大量的库,特别是网络库非常强大。
内置强大的工具,Go语言里面内置了很多工具链,最好的应该是gofmt工具,自动化格式化代码,能够让团队review变得如此的简单,代码格式一模一样,想不一样都很困难。
跨平台编译,如果你写的Go代码不包含cgo,那么就可以做到window系统编译linux的应用,如何做到的呢?Go引用了plan9的代码,这就是不依赖系统的信息。
内嵌C支持,Go里面也可以直接包含C代码,利用现有的丰富的C库。
服务器编程,以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。
分布式系统,数据库代理器等。
网络编程,这一块目前应用最广,包括Web应用、API应用、下载应用。
内存数据库,如google开发的groupcache,couchbase的部分组建。
每个Go源代码文件的开头都是一个package声明,表示该Go代码所属的包。包是Go语言里最基本的分发单位,也是工程管理中依赖关系的体现。
要生成Go可执行程序,必须建立一个名字为main的包,并且在该包中包含一个叫main()的函数(该函数是Go可执行程序的执行起点),一个文件夹里只能有一个main 函数,即只能有一个函数的入口。如果一定要将多个有main函数的代码放到一个文件中,则只需要在cmd中先编译,再运行(1. go build XXX.go 2. XXX.go )或者直接单独运行(go run)。
go build 命令:编译GO代码,生成一个可执行文件。go run 命令:不生成可执行文件,直接运行。
Go语言的main()函数不能带参数,也不能定义返回值。命令行传入的参数在os.Args变量 中保存。如果需要支持命令行开关,可使用flag包。后面我们将解释如何使用flag包来做命令行参数规范的定义,以及获取和解析命令行参数。
在包声明之后,是一系列的import语句,用于导入该程序所依赖的包。由于本示例程序用到了Println()函数,所以需要导入该函数所属的fmt包。
所有Go函数以关键字func开头。一个常规的函数定义包含以下部分:
func 函数名(参数列表)(返回值列表) {//左花括号的位置是固定在此位置,如果放到下一行,则会发生错误。
// 函数体
}
Go程序并不要求开发者在每个语句后面加上分号表示语句结束。
Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。大写字母和小写字母是不同的:heapSort和Heapsort是两个不同的名字。
1.声明的变量必须使用,声明的包也必须使用。2.只是声明没初始化的变量默认为0 3.同一个大括号里声明的变量名是唯一的。
4.变量初始化,var b int=10(声明时再赋值)。
或者先声明,再赋值。
var b int
b=20
最常用的是自动推到类型:
c:=10
根据初始化的值自动推到其类型。c:对于一个变量只能使用一次(初始化只需要初始化一次)
a:=10
fmt.Println("a=",a)//一段一段处理,直接处理一段,自动加换行
fmt.Printf("a=%d\n",a)//格式化处理,a的值放到%d的位置进行输出
使用起来Printf更加的方便控制格式,如:
//输出a,b,c三个数的值
a,b,c:=10,20,30
fmt.Println("a=",a,",b=",b,",c=",c)
fmt.Printf("a=%d,b=%d,c=%d\n",a,b,c)
//a,b,c三个数赋值
a,b,c:=10,20,30
//交换a,b值,和python 用法一样
a,b:=10,20
a,b=b,a
//可以这么理解,相当于左边的值是上边初始化的值,还没有发生变化,而后边改变后的值不影响左边值。
匿名变量
temp,_=a,b//匿名变量丢弃数据不做处理,所以只给temp赋值,配合函数返回值使用才有优势
变量声明需要var,常量声明需要const
const a int=10
//常量也可以自动推到类型,但是不需要使用:=
const a=10//自动推到类型
fmt.Println("a,%T\n",a)//%T代表显示a的类型
// 1 project main.go
package main
import (
"fmt"
)
func main() {
//多个变量定义方式1
//var a int
//var b float64
//多个变量定义方式2
var (
a int
b float64
)
a, b = 2, 3.2
fmt.Println("a=", a)
//fmt.Println("H")
fmt.Println("b=", b)
//多个常量定义方式1
// const c int = 2
// const d float64 = 3.2
//多个常量定义方式2
const (
c int = 2
d float64 = 3.2
)
fmt.Println("c=", c)
fmt.Println("d=", d)
}
package main
import "fmt"
func main() {
//1.iota常量自动生成器,每隔一行代码,自动累加1
//2.iota遇到const自动重置为0
const (
a = iota //0
b = iota //1
d int = 1
c = iota //2
)
//遇到const重置为0
const e = iota
fmt.Printf("a=%d,b=%d,c=%d,d=%d,e=%d\n", a, b, c, d, e)
//4.可以只写一个iota
const (
a1 = iota //0
b1 //1
c1 //2
)
fmt.Printf("a1=%d,b1=%d,c1=%d\n", a1, b1, c1)
//5.如果在同一行,值都一样
const (
i = iota
j1, j2, j3 = iota, iota, iota
k = iota
)
fmt.Printf("i=%d,j1=%d,j2=%d,j3=%d,k=%d\n", i, j1, j2, j3, k)
}
上表注释:byte只能放英文的字符,rune可以存放中文的字符,零值是指声明变量的初始值。
package main
import "fmt"
func main() {
//1、声明变量
var a bool
a = true
fmt.Println("a=", a)
//2.自动推到类型
const b = 10
fmt.Println("b=", b)
c := false
fmt.Println("c=", c)
//3、没有初始化,零值为false
var d bool
fmt.Println("d=", d)
}
package main
import "fmt"
func main() {
//1、声明变量
var a bool
a = true
fmt.Println("a=", a)
//2.自动推到类型
const b = 10
fmt.Println("b=", b)
c := false
fmt.Println("c=", c)
//3、没有初始化,零值为false
var d bool
fmt.Println("d=", d)
}
package main
import "fmt"
func main() {
//1.声明字符类型
var ch byte
ch = 97
//fmt.Println("ch=", ch) //这种打印得不到字符类型的结果
//格式化打印,%c以字符打印,%d以整形方式打印
fmt.Printf("%c,%d\n", ch, ch)
//2.字符是用单引号
ch = 'a'
fmt.Printf("%c,%d\n", ch, ch)
//大小写转化,之间相差32
fmt.Printf("小写转大写:%c\n", 'a'-32)
fmt.Printf("大写转小写:%c\n", 'A'+32)
}
package main
import "fmt"
func main() {
//1.声明变量
var str1 string
str1 = "abcd"
fmt.Println("str1=", str1)
//自动推到类型
str2 := "min"
fmt.Printf("str2 类型是%T", str2)
fmt.Printf("字符串长度是:%d", len(str2))
}
1)字符单引号,字符串双引号,2)字符元素一般只有一个,转义字符除外。字符串一般由一个或多个组成,字符串隐藏了一个转义字符‘\0’,
package main
import "fmt"
func main() {
//初始化
var t complex128
t = 2.1 + 3.14i
fmt.Println("t=", t)
//自动推导类型
t2 := 3.3 + 4i
fmt.Printf("t2 type is %T\n", t2)
//通过内置函数,取实部和虚部
fmt.Println("real(t2)=", real(t2), ",imag(t2)=", imag(t2))
}
打印格式 含义
%% 一个%字面量
%b 一个二进制整数值(基数为2),或者是一个(高级的)用科学计数法表示的指数为2的浮点数
%c 字符型。可以把输入的数字按照ASCII码相应转换为对应的字符
%d 一个十进制数值(基数为10)
%e 以科学记数法e表示的浮点数或者复数值
%E 以科学记数法E表示的浮点数或者复数值
%f 以标准记数法表示的浮点数或者复数值
%g 以%e或者%f表示的浮点数或者复数,任何一个都以最为紧凑的方式输出
%G 以%E或者%f表示的浮点数或者复数,任何一个都以最为紧凑的方式输出
%o 一个以八进制表示的数字(基数为8)
%p 以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示
%q 使用Go语法以及必须时使用转义,以双引号括起来的字符串或者字节切片[]byte,或者是以单引号括起来的数字
%s 字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符)
%t 以true或者false输出的布尔值
%T 使用Go语法输出的值的类型
%U 一个用Unicode表示法表示的整型码点,默认值为4个数字字符
%v 使用默认格式输出的内置或者自定义类型的值,或者是使用其类型的String()方式输出的自定义值,如果该方法存在的话
%x 以十六进制表示的整型值(基数为十六),数字a-f使用小写表示
%X 以十六进制表示的整型值(基数为十六),数字A-F使用小写表示
package main
import "fmt"
func main() {
a := 10
b := "abc"
c := 'a'
d := 2.1
//%T操作变量所属类型
fmt.Printf("%T,%T,%T,%T\n", a, b, c, d)
//输出数据
fmt.Printf("a=%d,b=%s,c=%c,d=%f\n", a, b, c, d)
//%v自动匹配格式
fmt.Printf("a=%v,b=%v,c=%v,d=%v\n", a, b, c, d)
}
package main
import "fmt"
func main() {
var a int
fmt.Printf("请输入变量a: ")
//阻塞等待用户的输入
fmt.Scanf("%d", &a) //不能忘了&
//另一种方法
fmt.Scan(&a)
fmt.Printf("a=", a)
}
package main
import "fmt"
func main() {
var a bool
a = true
//fmt.Printf("a=%d\n", a)
fmt.Printf("a=%t\n", a) //输出bool类型
//bool类型不能转化为整形
//fmt.Printf("a=%d\n", int(a)) //强制输出%d类型
//整形不能转化为bool类型
//不能转化的类型叫做不兼容类型
var ch byte
ch = 'a'
var t int
t = int(ch)//类型转换,把ch值转化为int
fmt.Printf("t=%d ", t)
}
给一个名字起一个别名
package main
import "fmt"
func main() {
type bigint int64 //给64起一个别名叫bigint
var a bigint
fmt.Printf("a type is %T\n", a)
type (
long int64
char byte
)
var b long = 11
var ch char = 'a'
fmt.Printf("b=%d,ch=%c", b, ch)
}
package main
import "fmt"
func main() {
fmt.Println("4>3 的结果", 4 > 3)
fmt.Println("4!=3的结果", 4 != 3)
//取反
fmt.Println("4>3 的结果", !(4 > 3))
fmt.Println("4!=3的结果", !(4 != 3))
fmt.Println("true && true", true && true)
//先&& 后||
fmt.Println(true && true || false)
}
package main
import "fmt"
func main() {
a := "王红"
if a == "王红" { //左括号必须与if在同一行
fmt.Println("true")
}
//if支持1个初始化语句(a:=10),初始化语句和判断条件(a==10)以分号分割
if a := 10; a == 10 { //条件为真则输出true
fmt.Println("true")
}
//if elseif else的使用
b := 10
if b == 10 {
fmt.Println("true")
} else {
fmt.Println("false")
}
if a := 10; a == 10 {
fmt.Println("true")
} else {
fmt.Println("false")
}
//多个if else
c := 9
if c == 10 {
fmt.Println("1")
} else if c < 10 {
fmt.Println("2")
} else {
fmt.Println("3")
}
if c := 9; c == 10 {
fmt.Println("1")
} else if c < 10 {
fmt.Println("2")
} else {
fmt.Println("3")
}
}
package main
import "fmt"
func main() {
//break默认包含
num := 1
switch num { //switch后面写的是变量本身
case 1:
fmt.Println("按下的是1楼")
//break不写也行,默认有
fallthrough//不跳出switch语句,后面的无条件执行
case 2:
fmt.Println("按下的是2楼")
//break
case 3:
fmt.Println("按下的是3楼")
//break
default:
fmt.Println("按下的是3楼")
}
}
package main
import "fmt"
func main() {
//for 初始化条件;判断条件;条件变化{
// }
//1+2+3....+100
sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
fmt.Println("sum= ", sum)
}
package main
import "fmt"
func main() {
//配合数组或者切片使用
str := "abc"
//for 打印
for i := 0; i < len(str); i++ {
fmt.Printf("str[%d]=%c\n", i, str[i])
}
//range打印,默认返回两个值
for i, ite := range str {
fmt.Printf("str[%d]=%c\n", i, ite)
}
//r第二个返回值默认丢弃
for i := range str {
fmt.Printf("str[%d]=%c\n", i, str[i])
}
for i, _ := range str {
fmt.Printf("str[%d]=%c\n", i, str[i])
}
}
package main
import "fmt"
import "time"
func main() {
i := 0
for { //for 后面不写任何东西,那么这个循环条件永远为真,即死循环
i++
time.Sleep(time.Second) //延时1秒
if i == 5 {
//break
continue
}
fmt.Println("i= ", i)
}
}
package main
import "fmt"
//import "time"//导入的包必须使用,要不然会发生错误
func main() {
//break //break 只能使用 in a loop, switch, or select
//goto 任何地方都可以使用,但是不能跨函数使用
fmt.Println("11111")
goto END //goto 是关键字 END是用户起的名字,叫做标签
fmt.Println("222222")
END:
fmt.Println("333333")
}
package main //必须有一个main包
import "fmt"
//无参无返回函数的定义
func MyFunc() {
a := 333
fmt.Println("a= ", a)
}
func main() { //必须有一个入口
MyFunc() //调用函数
}
package main //必须有一个main包
import "fmt"
//有参无返回函数的定义,普通参数列表
//定义参数时,括号中的参数是形参
func MyFunc(a int) { //圆括号中定义参数,括号中定义参数少了关键字var
fmt.Println("a= ", a)
}
//多个参数传递
func MyFunc01(a int, b int) { // (a,b int)
fmt.Printf("a= %d, b= %d\n", a, b)
}
//传递不同类型的参数
func MyFunc01(a int, b string, c float64) {
fmt.Printf("a=%d,b=%d\n", a, b)
}
func MyFunc01(a, b int, c string, d, e float64) {
fmt.Printf("a=%d,b=%d\n", a, b)
}
func main() { //必须有一个入口
//有参无返回值调用格式:函数名(所需参数)
//调用函数传递的参数叫实参
//实参只能传递给形参
MyFunc(666) //调用函数
MyFunc01(111, 222)
}
package main //必须有一个main包
import "fmt"
func MyFunc01(args ...int) { //传递的实参可以是0个,也可以是多个
fmt.Println("len(args)=", len(args)) //获取用户传递参数的个数
for i := 0; i < len(args); i++ {
fmt.Printf("args[%d]=%d\n", i, args[i])
}
for i, data := range args {
fmt.Printf("args[%d]=%d\n", i, data)
}
}
//一个是不定参数,一个是确定的参数
//固定参数一定要传参,不定参数可以根据需求传参
func MyFunc01(a int, args ...int) {
}
//不定参数只能放到参数列表的最后一个
//错误示范
/*
func MyFunc01(args ...int,a int) {
}
*/
func main() { //必须有一个入口
MyFunc01()
fmt.Println("++++++++++++++++++++++++++")
MyFunc01(1)
fmt.Println("++++++++++++++++++++++++++")
MyFunc01(1, 2, 3)
}
package main
import "fmt"
func MyFunc(tmp ...int) {
for _, data := range tmp {
fmt.Println("tmp= ", data)
}
}
func MyFunc1(tmp ...int) {
for _, data := range tmp {
fmt.Println("tmp= ", data)
}
}
func test(args ...int) {
//全部元素传递给MyFunc
MyFunc(args...)
//只想把后两个参数传递给MyFunc1
MyFunc1(args[2:]...) //从args[2]开始(包含本身),把后面的所有元素传递过去
}
func main() {
test(1, 2, 3, 4)
}
package main
import "fmt"
//无参有返回值:只有一个返回值
//有返回值的函数需要通过return返回
func myfunc01() int {
return 666
}
//给返回值变量起一个名字,最常用的写法
func myfunc02() (result int) {
result = 666
return
}
func main() {
//无参有返回值函数调用
var a int
a = myfunc01()
fmt.Println("a=", a)
b := myfunc01()
fmt.Println("b=", b)
c := myfunc02()
fmt.Println("c=", c)
}
package main
import "fmt"
func myfunc01() (int, int, int) {
return 1, 2, 3
}
// go推荐写法
func myfunc02() (a int, b int, c int) { //(a,b,c int)
a, b, c = 111, 222, 333
return
}
func main() {
a, b, c := myfunc02()
fmt.Printf("a=%d,b=%d,c=%d", a, b, c)
}
package main
import "fmt"
func myfunc01(a, b int) (max, min int) {
if a > b {
max = a
min = b
} else {
max = b
min = a
}
return
}
func main() {
max, min := myfunc01(10, 20)
fmt.Printf("max=%d,min=%d", max, min)
}
/*
package main
import "fmt"
func myfunc02() (b int) {
b = 222
fmt.Println("mufunc02 b", b)
return
}
func myfunc01() (a int) {
a = 111
//调用另外一个函数
b := myfunc02()
fmt.Println("myfunc01 b=", b)
fmt.Println("myfunc02 a=", a)
return
}
func main() {
a := myfunc01()
fmt.Printf("a=%d", a)
}
*/
package main
import "fmt"
func funcc(c int) {
fmt.Println("c= ", c)
}
func funcb(b int) {
funcc(b - 1)
fmt.Println("b= ", b)
}
func funca(a int) {
funcb(a - 1)
fmt.Println("a= ", a)
}
func main() {
funca(3)
fmt.Println("main")
}
package main
import "fmt"
func test(a int) {
if a == 1 {
return
}
fmt.Println("a= ", a)
test(a - 1)
}
//实现1+2+3+....+100
func add(a int) (sum int) {
if a == 1 {
return 1
} else {
return a + add(a-1)
}
}
func main() {
test(3)
fmt.Println("main")
b := add(100)
fmt.Println("b=", b)
}
package main
import "fmt"
func Add(a, b int) int {
return a + b
}
func minus(a, b int) int {
return a - b
}
//函数也是一种数据类型,通过type给一个函数类型起名
//Functype是一个函数类型,Functype是func(int,int)int函数类型的名字
type Functype func(int, int) int //没有函数名字,没有大括号
func main() {
var result int
result = Add(1, 2)
fmt.Println("result= ", result) //传统调用方法
//声明一个函数类型的变量,变量名叫fTest
var fTest Functype
fTest = Add //给这个函数类型的变量赋值
result = fTest(10, 20) //等价于Add(10,20)
fmt.Println("result2= ", result)
fTest = minus
result = fTest(10, 5) //等价于minus(10,5)
fmt.Println("result3= ", result)
}
package main
import "fmt"
//回调函数:函数有一个参数是函数类型,这个函数就是回调函数
type Functype func(int, int) int //定义一个函数类型,名字是Functype
//多态:多种形态,调用同一个接口,不同的表现,可以实现不同的功能,加减乘除
//先有想法,后面再实现函数功能
//实现加法功能
func Add(a, b int) int {
return a + b
}
//实现减法
func minus(a, b int) int {
return a - b
}
func Calc(a, b int, fTest Functype) (result int) { //Calc这个函数可以拓展
fmt.Println("calc")
result = fTest(a, b) //这个函数还没有实现??
return
}
func main() {
a := Calc(1, 1, Add)
fmt.Println("a= ", a)
b := Calc(1, 1, minus)
fmt.Println("b= ", b)
}
package main
import "fmt"
func main() {
a := 10
str := "mike"
//匿名函数,没有函数名字
f1 := func() { //函数只是定义了,还没有调用,匿名函数形成的内部区域叫做闭包,匿名函数
//可以调用函数外部的变量,如a,str
fmt.Println("a= ", a)
fmt.Println("str= ", str)
}
f1()
//定义无参数的匿名函数,同时调用
func() {
fmt.Printf("a=%d,str=%s\n", a, str)
}() //后面的()代表调用此匿名函数,因为无参数,所以括号里面为空。
//定义带有参数的匿名函数
f3 := func(i, j int) {
fmt.Printf("i=%d,j=%d\n", i, j)
}
f3(1, 2)
//定义匿名函数同时调用
func(i, j int) {
fmt.Printf("i=%d,j=%d\n", i, j)
}(10, 20)
//定义有参数有返回值的匿名函数
x, y := func(i, j int) (max, min int) {
if i > j {
max = i
min = j
} else {
max = j
min = i
}
return
}(10, 20)
fmt.Printf("x=%d,y=%d", x, y)
}
package main
import "fmt"
//闭包内部改了之后,这个变量将改变
func main() {
a := 10
str := "wanghong"
func() { //闭包以引用方式,捕获外部变量,闭包内部改变变量,外部也将会改变
a = 666
str = "go"
fmt.Printf("内部:a=%d,str=%s\n", a, str)
}() //括号代表直接调用
fmt.Printf("外部:a=%d,str=%s\n", a, str)
}
package main
import "fmt"
func test01() int {
//函数被调用时,x才分配空间,才初始化为0。函数调用完毕,x自动释放为0
var x int //没有初始化,值为0
x++
return x * x
}
//函数的返回值是一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数
func test02() func() int {
var x int
return func() int {
x++
return x * x
}
}
func main() {
//函数的返回值是一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数
//它不关心不活的变量和常量是否已经超出了作用域
//所以只要有闭包还在使用它,这些变量就会存在(不会被释放为0)
f := test02()
fmt.Println(f()) //1
fmt.Println(f()) //4
fmt.Println(f()) //9
fmt.Println(f()) //16
}
func main01() {
fmt.Println(test01())
fmt.Println(test01())
fmt.Println(test01())
fmt.Println(test01())
}
package main
import "fmt"
func main() {
//defer只能在函数或方法的内部使用
//defer 延迟调用,main函数结束前调用
defer fmt.Println("bbbbbbbbbbbbbbb")
fmt.Println("aaaaaaaaaaaa")
}
/*
输出为
aaaaaaaaaaaa
bbbbbbbbbbbbbbb
如果没有defer输出为
bbbbbbbbbbbbbbb
aaaaaaaaaaaa
*/
package main
import "fmt"
func test(x int) {
100 / x
}
func main() {
//defer只能在函数或方法的内部使用
//defer 延迟调用,main函数结束前调用
fmt.Println("aaaaaaaaaaaa")
fmt.Println("bbbbbbbbbbbbbbb")
//调用一个函数导致内存出问题
test(0)
fmt.Println("cccccccccccccccccc")
}
上面的程序由于0不能当被除数,所以发生了错误,结果如下
程序崩溃了之后,后面的“cccccccccccccccccccc”没有被打印
程序加了defer 之后
package main
import "fmt"
func test(x int) {
result := 100 / x
fmt.Println("result=", result)
}
func main() {
//defer只能在函数或方法的内部使用
//defer 延迟调用,main函数结束前调用
defer fmt.Println("aaaaaaaaaaaa")
defer fmt.Println("bbbbbbbbbbbbbbb")
//调用一个函数导致内存出问题
test(0)
defer fmt.Println("cccccccccccccccccc")
}
结果为:先写defer的后调用 ,先进后出的顺序,在结果快执行完前执行按先写后执行的顺序执行defer语句
给test(0)前面加了defer之后,
哪怕某一个程序发生错误,这些调用依旧会执行。
package main
import "fmt"
func main() {
a := 10
b := 20
defer func() {
fmt.Printf("内部:a=%d,b=%d\n", a, b)
}() //()代表调用此匿名函数
a = 111
b = 222
fmt.Printf("外部:a=%d,b=%d\n", a, b)
}
结果为:
package main
import "fmt"
func main() {
a := 10
b := 20
defer func(a, b int) {
fmt.Printf("内部:a=%d,b=%d\n", a, b)
}(a, b) //()代表调用此匿名函数
a = 111
b = 222
fmt.Printf("外部:a=%d,b=%d\n", a, b)
}
结果显示:
是因为执行到defer的时候,已经先传递参数了,此时的a=10,b=20,但是还没有调用。
package main
import "fmt"
import "os"
func main() {
//接受用户传递的参数,都是以字符串方式传递的
list := os.Args
n := len(list)
fmt.Println("n= ", n) //结果是1
//输入 xxx.exe a b
for i := 0; i < n; i++ {
fmt.Printf("list[%d]=%s\n", i, list[i])
}
}
结果为:
package main
import "fmt"
func test() {
a := 10
fmt.Println("a=", a)
}
func main() {
//定义在{}里面的变量就是局部变量,只能在{}里面有效
//执行到定义变量那句话,才开始分配空间,离开作用域自动释放
//作用域,变量其作用的范围
// a = 111//显示无定义a
/*
{
i := 10
fmt.Println("i= ", i)
}
i = 111//显示i没有定义
*/
/*
if flag := 3; flag == 3 {
fmt.Println("flag=", flag)
}
flag = 4//显示flag无定义,因为flag是定义在if语句中的
*/
}
package main
import "fmt"
//定义在函数外部的变量是全局变量
var a int
func test() {
fmt.Println("test a=", a)
}
func main() {
a = 10
fmt.Println("a= ", a)
test()
}
package main
import "fmt"
var a byte //定义一个全局变量
func main() {
var a int
//1.不同作用域,允许定义同名变量
//2.使用变量的原则,就近原则
fmt.Printf("%T\n", a)//int
{
var a float32
fmt.Printf("%T\n", a)//float32
}
}
package main
//忽略此包
import _ "fmt"
func main() {
}
/*
//给包名起别名
import io "fmt"
func main() {
io.Println("this is a test")
}
*/
/*
//.操作:调用函数无需包名
import . "fmt"
import . "os"
//点操作很容易使包的名和变量名一样,如Println或者Args类型的变量
func main() {
Println("this is a test")
Println("Args=", Args)
}
*/
/*
//方式1
import "fmt"//导入包:导入包之后必须使用,否则编译不过
import "os"
//方式2:常用
func main(){
fmt.Println("this is a test")
fmt.Println("os.Args=",os.Args)
}
*/