一、 文件名&关键字&标识符
- 所有go源码都是以.go结尾
- 标识符以字母或下划线开头,大小写敏感
- 下划线_是特殊标识符,用户忽略结果
- 保留关键字
- 导入包时可以设置别名
下面是保留关键字:
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthough | if | range | type |
continue | for | import | return | var |
二、 Go程序基本结构
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello world")
}
- 任何一个代码必须隶属一个包
- import关键字,引入其他包
- golang可执行程序,package main并且只有一个main入口函数
- 包中函数调用,同一个函数中可以直接调用;不用包中函数,通过包名+点+函数名进行调用
- 包访问控制规则,大写意味着这个函数或者变量可以导出的,及在其他包内是可以调用的;小写以为这个函数或者变量是私有的,包外部不能访问。
小练习1:
写一个小程序,对于给定的一个数字n,求出所有两两相加等于n的组合
package main
import (
"fmt"
)
func add_num(n int){
for i:=0;i<=n;i++{
fmt.Printf("%d+%d=%d\n",i,n-i,n)
}
}
func main(){
add_num(5)
}
小练习2:
写一个小程序,包含两个包,add和main,其中add包中有两个变量:Name,和age,请问main包中如何访问Name和age?(用于理解go中大小写敏感的问题)
add包中代码:
package add
var Name string = "luck"
var age int = 23 //测试证明小写是不能被其他包调用
go中的大写可以理解为其他语言中的public,小写理解为private
main包代码:
package main
import (
"fmt"
"GoWork/day02/add_examples"
)
func main() {
fmt.Println(add.Name)
}
如果把add包中代码改为:
package add
var Name string
var Age int
Name = "zhaofan"
Age = 23
这个写法也是错误的,gp作为编译型语言,必须通过函数来进行语句的执行,而不能在函数外执行语句
小练习3:
如果使用第三方包,可以改成自己能快速识别的,或者定义规则的别名引用,以下对add这个包设置成叫a的别名
package main
import (
"fmt"
a "go_learning/day2/acc_example2/add" //别名
)
func main() {
fmt.Println(a.Name, a.Age)
}
小练习4:
每个源文件都可以包含一个init函数,这个init函数自动被go运行框架调用
package main
import (
"fmt"
)
func init(){
fmt.Println("执行初始化函数")
}
func main() {
fmt.Println("hello world")
}
运行结果是先打印init函数内容,后打印main内容
三、函数的声明和注释
函数声明
格式为:func 函数名字(参数列表)(返回值列表) 例子如下:
func add(){
}
func add(a int,b int) int{
}
func add(a int,b int) (int int){
}
注释
单行注释//
func main() {
// fmt.Println("hello world")
}
多行注释 /**/
/*
func main() {
fmt.Println("hello world")
}
*/
四、 数据类型和操作符
数据类型用于声明函数和变量 数据类型到出现是为了把数据分成所需内存大小不同到数据,编程到时候用大数据的时候才需要申请大内存,就可以充分利用内存。
常见数据类型及分类
- 布尔型: 布尔型的值只可以是常量true或者false。例如:var b = true
- 数字类型: 整型int和浮点型float32、float64,Go语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。
- 字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 语言的字符串的字节使用UTF-8编码表示Unicode文本
- 派生类型: 包括指针类型(Pointer)、 数组类型、结构化类型(struct)、 Channel类型、函数类型、切片类型、接口类型(interface)、Map(类型)
注意:
字符串的时候用双引号""
,这里也可以用反引号,通过反引号的方式会保留你的格式,不会对你的内容做任何转义
字节的时候用单引号''
,同样也可以通过反引号`
var cc byte = 'c' fmt.println(ccc)
var cc byte = c fmt.println(cc)
一个会打印c的ASCII,一个会打印c
数据类型
Go也有基于架构的类型,例如:int、uint、uintotr。无符号的数不能为负数,有符号的可以为负数
数字类型
- unit8: 无符号8位整型(0-255)
- uint16:无符号16位整型(0-65535)
- unit32:无符号32位整型(0-4294967295)
- uint64:无符号64位整型(0到18446744073709551615)
- int8:有符号8位数(-128到127)
- int16:有符号16位整型(-32768到32767)
- int32:有符号32位整型(-2147483648到2147483647)
- int64:有符号64位整型(-9223372036854775808 到 9223372036854775807)
浮点型
- float32:IEEE-754 32位浮点型数
- float64:IEEE-754 64位浮点型数
- complex64:32位实数和虚数
- complex128:64位实数和虚数
其他数字类型
- byte:类似uint8
- rune:类似int32
- uint:32或64位
- int:与uint 一样大小
- uintptr:无符号整型,用于存放一个指针
类型转换
举个例子来理解: var a int = 8
转换为int32 var b int32 = int32(a)
当我们代码中设计到数据计算的时候,要保证两个数据类型完全相同,
var a int 和 var b int32 是不能直接做计算处理的,这个时候就需要用到类型转换
相关操作符
!
&&
||
分别表示非,与,或
==
、=
、!=
、 <
、>
、<=
、>=
练习1(随机数): 使用math/rand生成随机整数,10个小于100的随机整数以及10个随机浮点数
func init() {
rand.Seed(time.Now().Unix())
}
func main() {
for i := 1;i < 10;i++ {
fmt.Println(rand.Intn(100)) //
fmt.Println(rand.Float64())
}
}
但是这里会造成每次运行程序生成的随机数是相同的,解决方式是加入随机种子:rand.Seed(time.Now().Unix())
五、常量
常用cost修饰,代表永远是只读不能修改 const只能修饰boolean,number(int相关类型,浮点类型,complex)和string 语法
const 变量名 [变量类型] = value其中变量类型可以省略
例子
const b string = "hello"
const b int = 23
通常定义常亮的写法
const (
a = 0
b = 1
)
高级方法
const (
a = iota
b
c
)
这里自动回吧a赋值为0,后面的变量一次加1
六、变量
声明变量和赋值语法
- 可以先用var声明,然后用等号赋值;
- 也可以用:=把上面两步合并为一步。
- 区别:=仅用于已经声明过的变量;而:=是声明加赋值。——可参考编译错误信息。
可以先用var声明,然后用等号赋值
var name string
name = "luck"
合并到一起
var name string = "luck"
也可以在声明时同时赋值,可以省略变量类型,(不建议根据初始值来判断变量类型这种方法,go是强类型语言,定义变量最好指定变量类型)
var name = "luck"
Go语言还提供一种更简短到写法
- 使用变量的首选形式
- 只能被用在函数体内
- 不可以用于全局变量的声明与赋值
name := "luck"
变量的作用域
在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部
在函数外部生命的变量叫做全局变量,生命周期作用域整个包,如果是大写,作用域整个程序
在函数内的语句块的内的变量只在语句块,生命周期就是仅限于语句块内.这里主要指{}
括起来的语句块
理解作用域:
package main
import (
"fmt"
)
var a string = "luck"
func test1() {
fmt.Println(a)
}
func test2() {
a := "bigbigY"
fmt.Println(a)
}
func main() {
test1()
test2()
}
值类型和引用类型
值类型:变量直接存储值,即变量直接指向存在内存中的值。内存通常在栈中分配 值类型通常包括基本数据类型int,float,bool,string以及数组和struct
package main
import (
"fmt"
)
func main() {
a := 5
b := a
fmt.Printf("a = %d,a的内存地址为: %v,b = %d,b的内存地址为:%v",a,&a,b,&b)
}
这个时候a和b的值都为5 其实这里内存中是将i的值进行了拷贝,我们通过&获取变量的内存地址也可以看出 &i和&j 的内存地址是不同的,所以我如果在var j int = i,后继续更改i变量的值,并不会影响j的值,因为是不同的内存地址存放的值
引用类型:变量存的是一个地址,这个地址存储最终的值,内存通常在堆上分配。通过GC回收 一个引用类型的变量 r1 存储的是 r1 的值所在的内存地址(数字),或内存地址中第一个字所在的位置。 引用类型通常包括指针,slice,map,chan等。 所以如果我们定义了两个引用类型变量像上面的值类型一样进行赋值操作则两者都会改变,因为两者的引用地址是相同的。 例子:
package main
import (
"fmt"
)
func main() {
var a int = 5
var b chan int = make(chan int,1)
c := b
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
输出
5
0xc42005c070
0xc42005c070
练习(交换2个数的值):
package main
import (
"fmt"
)
func swap(a *int,b *int) {
tmp := *a
*a = *b
*b = tmp
}
func main() {
var first int = 100
var two int = 200
swap(&first,&two)
fmt.Println(first,two)
}