一、基础知识
1.Go内置关键字和注释方法
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
2.Go程序的一般结构
//当前程序的包名
package main
// 导入其它的包
import "fmt"
// 全部变量的声明与赋值
var name = "gopher"
// 一般类型的声明
type newType int
// 结构体的声明
type gopher struct{}
// 接口的声明
type golang interface{}
// 由main函数作为程序入口点启动
func main() {
fmt.Println("Hello World!")
}
3.包的导入
- package 别名与省略调用
// 别名:
import std "fmt"
// 省略调用(这样可以不用写包名,直接调用):
import . "fmt"
// 初始化,但不调用:
import _ "github.com/go-sql-driver/mysql"
- 可见性规则
只有首字母为大写的变量、方法、函数等才能被其它包调用(类似面向对象里面的属性public 和private)
二、类型与变量
1.基本类型
| 类型 | 长度 | 默认值 | 说明 |
|---|---|---|---|
| bool | 1 | false | 不能使用0、1代替false、true |
| byte | 1 | 0 | 等同于uint8 |
| int、uint | 4、8 | 0 | 默认整数类型,根据平台,32或64位 |
| int8、uint8 | 1 | 0 | -128 ~ 127,0 ~ 255 |
| int16、uint16 | 2 | 0 | -32768 ~ 32767,0 ~ 65535 |
| int32、uint32 | 4 | 0 | -(2^32 / 2) ~ 2^32 / 2 - 1,0 ~ 2^32 |
| int64、uint64 | 8 | 0 | -(2^64 / 2) ~ 2^64 / 2 - 1,0 ~ 2^64 |
| float32、float32 | 4 | 0.0 | |
| float64、float64 | 8 | 0.0 | 默认浮点数类型 |
| complex64 | 8 | ||
| complex128 | 16 | ||
| rune | 4 | 0 | Unicode Code Point, int32 |
| uintptr | 4,8 | 0 | 足以存储指针的uint |
| string | "" | 字符串,默认值为空字符串,而非NULL | |
| array | 数组 | ||
| struct | 结构体 | ||
| function | nil | 函数 | |
| interface | nil | 接口 | |
| map | nil | 字典,引用类型 | |
| slice | nil | 切片,引用类型 | |
| channel | nil | 通道,引用类型 |
2.类型别名
设置类型别名后可以让代码可读性更强,一目了然这个变量做什么用的:
type ByteSize int64
func main(){
var a ByteSize = 1
fmt.Println(a)
}
这里变量 a 的静态类型是 ByteSize ,底层类型是 int64。
3.变量的声明与赋值
- 变量的声明: var a int
- 变量的赋值:a = 123
- 声明并赋值: var a int = 123 (此时若省略类型,则编译器根据值自动推导类型)
- 多个变量的声明
并行方式(可以省略类型,由值推导)
var a, b, c, int = 1, 2, 3
函数内部声明变量的简写形式:
funciont main(){
a:= 1
}
函数多个返回值时可以用"_"忽略返回值
a, _, c, d := 1, 3, 4
4.类型转换
- go中不存在隐式转换,所有类型转换必须显示声明
- 转换只能发生在两种相互兼容的类型之间
- 类型转换的格式:
var a float32 = 1.1
b := int(a)
- 语法歧义
如果转换的目标是指针、单向通道或没有返回值的函数类型,那么必须使用括号,以避免造成语法分解错误。
fun main() {
x := 100
p := *int(&x) // 错误:cannot convert &x (type *int) to type int
// invalid indirect of int(&x) (type int)
fmt.Println(p)
}
正确的做法是用括号,让编译器将*int解析为指针类型。
(*int)(p)
(<-chan int)(c)
(func())(x)
三、常量与运算符
1.常量的定义
-
常量的值在编译时就已经确认
-
常量的定义格式与变量基本相同
-
等号右侧必须是常量或者常量表达式
-
常量表达式中的函数必须是内置函数
// 定义单个常量
const a int = 1
const b = "A"
const (
text = "123"
length = len(text)
num = b * 20
)
// 同时定义多个变量
const i, j, k = 1, "2", "3"
const (
text2 ,length2, num2 = "456", len(text2), k* 10
)
2.常量的初始化规则
- 在定义常量组时,如果不提供初始值,则表示使用上行的表达式
var a = 1
const (
b = a
// 此时报错,因为全局变量在编译时不能确定值,常量必须是编译时能确定值的或使用内置函数获得的值(eg:len())
)
const (
a = "A"
b
c
// 此时 a,b,c都为"A"
)
const (
a, b = 1, "A"
c, d
// a,c为1,b,d为"A"。此时注意下行的常量个数必须与上行数量保持一致
)
3.常量的枚举
-
使用相同的表达式不代表具有相同的值
-
iota是常量的计数器,从0开始,组中每定义1个常量自动递增1
-
通过初始化规则与iota可以达到枚举的效果
-
每遇到一个const关键字,iota就会重置为0
const (
a = "A"
b
c = iota
d // d的值为3,因为在常量组中,定义了4个变量所以iota计数器从0开始计数4次,所以为3
)
4.运算符
// 优先级从高到低
* / % << >> & &^
= + - | ^
== != < <= >= >
&&
||
位的操作:
/*
6的二进制:0110 第一个
10的二进制:1011 第二个
---------
按位与: & 0010 = 2 (两个都是1才为1)
按位或: | 1111 = 15 (一个是1就是1)
按位异或:^ 1101 = 13 (两个只有一个是1才是1)
按位清除:&^ 0100 = 4 (第一个与第二个操作数对应都为1的重置为0,否则与第一位相同)
*/
四、控制语句
1.基础知识补充
指针:
不能将内存地址与指针混为一谈。内存地址是内存中每个字节单元的唯一编号,而指针则是一个实体。指针会分配内存空间,相当于一个专门用来保存地址的整型变量。
func main() {
x := 100
var p *int = &x // 获取地址,保存到指针变量
*p += 120 // 用指针间接引用,并更新对象
println(p, *p) // 输出指针所存储的地址,以及目标对象
}
输出:
0xc82003df30 220
go 虽然保留了指针,但是与其它编程语言不同的是,在 go 当中不支持指针运算以及 -> 运算符,而直接采用 . 选择符来操作指针目标对象的成员
-
操作符
&取变量地址,使用*通过指针间接访问目标对象 -
默认值为 nil 而非 null
递增递减语句
在go中,++ 与 -- 是作为语句而并不是作为表达式
a := 1
a++
// 但不能这样:a := a++,只能作为单独的语句独占一行
2.if 判断语句
-
条件表达式没有括号
-
支持一个初始化表达式(可以是并行方式)
-
左大括号必须和条件语句或else在同一行
-
支持单行模式
-
初始化语句中的变量为block级别,同时隐藏外部同名变量
func main(){
a := 10
if a:=1 {
fmt.Println(a)
}
fmt.Println(a)
}
//输出为: 1 10
3.for循环语句
- go 只有 for 一个循环语句关键字,但支持3种形式
// 第一种(同其他语言的while true {}):
func main() {
a := 1
for {
a++
if a > 3{
break
}
}
fmt.Println(a)
}
// 第二种(同其他语言的:while a <= 3 {}):
func main() {
a := 1
for a <= 3 {
a++
}
fmt.Println(a)
}
// 第三种:
func main() {
a := 1
for i := 0; i <= 3; i++ {
a++
}
fmt.Println(a)
}
// 第四种:迭代 array、slice、map、chan
func main() {
a := []int[1,2,3,4,5]
for k, v := range a {
fmt.Println(a)
}
}
-
初始化和步进表达式可以是多个值
4.switch选择语句
go 语言中无须对每个 case 手动书写 break 以阻止程序继续向下匹配。如果要达到继续匹配的目的可以使用关键字:fallthrough
func main() {
a := 1
switch a {
case 0:
fmt.Println("a=0")
case 1:
fmt.Println("a=1")
}
fmt.Println(a)
}
func main() {
a := 1
switch {
case a >= 0:
fmt.Println("a=0")
fallthrough
case a >= 1:
fmt.Println("a=1")
}
fmt.Println(a)
}
//此时a的作用域只在switch表达式之内
func main() {
switch a := 1 {
case a >= 0:
fmt.Println("a=0")
fallthrough
case a >= 1:
fmt.Println("a=1")
}
fmt.Println(a)
}
5.跳转语句
break、continue、goto 配合标签使用,与其他语言相似