var name type
其中,var 是声明变量的关键字,name 是变量名,type 是变量的类型
var (a intb stringc []float32d func() boole struct {x int}
)
名字 := 表达式
i, j := 0, 1
需要注意的是,简短模式(short variable declaration)有以下限制:
定义变量,同时显式初始化。 //相当于赋值,可以不用再声明获取到的变量的类型
不能提供数据类型。 // 因为赋值直接会有类型了,所以不用提供数据类型
只能用在函数内部。 //全局定义还是得用var
示例:
func main() {x:=100a,s:=1, "abc"
}
var 变量名 类型 = 表达式
var hp int = 100
上面代码中,100 和 int 同为 int 类型,int 可以认为是冗余信息,因此可以进一步简化初始化的写法
var defence =
var damageRate float32 = 0.17
var damage = float32(attack-defence) * damageRate
fmt.Println(damage)
代码说明:
如果 hp 已经被声明过,但依然使用:=时编译器会报错
// 声明 hp 变量
var hp int
// 再次声明并赋值
hp := 10
示例:
conn, err := net.Dial(“tcp”,“127.0.0.1:8080”) net.Dial
提供按指定协议和地址发起网络连接,这个函数有两个返回值,一个是连接对象(conn),一个是错误对象(err)
var b = 200
b, a = a, b
fmt.Println(a, b)
import ("fmt"
)
func main() {//声明局部变量 a 和 b 并赋值var a int = 3var b int = 4//声明局部变量 c 并计算 a 和 b 的和c := a + bfmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
import "fmt"
//声明全局变量
var c int
func main() {//声明局部变量var a, b int//初始化参数a = 3b = 4c = a + bfmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
import ("fmt"
)
//全局变量 a
var a int = 13
func main() {//局部变量 a 和 bvar a int = 3var b int = 4fmt.Printf("main() 函数中 a = %d\n", a)fmt.Printf("main() 函数中 b = %d\n", b)c := sum(a, b)fmt.Printf("main() 函数中 c = %d\n", c)
}
func sum(a, b int) int {fmt.Printf("sum() 函数中 a = %d\n", a)fmt.Printf("sum() 函数中 b = %d\n", b)num := a + breturn num
}
import ("fmt""math"
)
func main() {fmt.Printf("%f\n", math.Pi)fmt.Printf("%.2f\n", math.Pi)
}
通用占位符:
布尔型:
宽度标识符具体见下图:
n := 12.34
fmt.Printf("%f\n", n)
fmt.Printf("%9f\n", n)
fmt.Printf("%.2f\n", n)
fmt.Printf("%9.2f\n", n)
fmt.Printf("%9.f\n", n)输出:
12.340000
12.340000
12.3412.3412
package main
import "fmt"
func main() {i := 0var c float32 = 0.2b := float32(sum(3, 4))if b > 7 {i = 1}fmt.Printf("当前c的值为:%.2f\n", c)fmt.Printf("当前i的值为:%d\n", i)b2 := isBool(2)fmt.Printf("b2的值为: %t\n", b2)
}
func sum(a, b int) int {return a + b
}
func isBool(i int) bool { return i != 0 }
\n:换行符
\r:回车符
\t:tab 键
\u 或 \U:Unicode 字符
\:反斜杠自身
使用 `符号来定义
内部字符串以原始文字输出,转义符号失效
package main
import "fmt"
func main() {const str1 = `第一行
第二行
第三行
\r\n
`fmt.Printf("str1:%v", str1)
}
package main
import "fmt"
func main() {tip1 := "gen ji is a ninja"fmt.Println(len(tip1))tip2 := "忍者"fmt.Println(len(tip2))
}输出:
17 // 纯英文与空格只占用一个长度
6 //一个汉字占用三个长度
package main
import ("fmt""unicode/utf8"
)
func main() {fmt.Println(utf8.RuneCountInString("龙龟冲!"))fmt.Println(utf8.RuneCountInString("龙龟, Fight!"))
}
ASCii码输出
theme := "狙击 start"
for i := 0; i < len(theme); i++ {fmt.Printf("ascii: %c %d\n", theme[i], theme[i])
}
Unicode编码输出
package main
import "fmt"
func main() {theme := "狙击 start"for i, s := range theme {fmt.Printf("%d Ascii: %c %d\n", i, s, s)}
}输出:
0 Ascii: 狙 29401
3 Ascii: 击 20987
6 Ascii: 32
7 Ascii: s 115
8 Ascii: t 116
9 Ascii: a 97
10 Ascii: r 114
11 Ascii: t 116
tracer := "死神来了, 死神bye bye"
comma := strings.Index(tracer, ", ")
pos := strings.Index(tracer[comma:], "死神") //等价于从", 死神bye bye"字符串开始查找
fmt.Println(comma, pos, tracer[comma+pos:])输出:
12 3 死神bye bye
package main
import ("bytes""fmt"
)
func main() {a := "今天"b := "不错"var stringBuffer bytes.BufferstringBuffer.WriteString(a)stringBuffer.WriteString(b) //这种拼接方式比+号高效fmt.Println(stringBuffer.String())
}
精度丢失问题
package main
import ("fmt""math"
)
func main() {// 输出各数值范围fmt.Println("int8 range:", math.MinInt8, math.MaxInt8)fmt.Println("int16 range:", math.MinInt16, math.MaxInt16)fmt.Println("int32 range:", math.MinInt32, math.MaxInt32)fmt.Println("int64 range:", math.MinInt64, math.MaxInt64)// 初始化一个32位整型值var a int32 = 1047483647// 输出变量的十六进制形式和十进制值fmt.Printf("int32: 0x%x %d\n", a, a)// 将a变量数值转换为十六进制, 发生数值截断b := int16(a)// 输出变量的十六进制形式和十进制值fmt.Printf("int16: 0x%x %d\n", b, b)// 将常量保存为float32类型var c float32 = math.Pi// 转换为int类型, 浮点发生精度丢失fmt.Println(int(c))
}
当使用&操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*操作符,也就是指针取值,代码如下
package main
import ("fmt"
)
func main() {// 准备一个字符串类型var house = "Malibu Point 10880, 90265"// 对字符串取地址, ptr类型为*stringptr := &house// 打印ptr的类型fmt.Printf("ptr type: %T\n", ptr)// 打印ptr的指针地址fmt.Printf("address: %p\n", ptr)// 对指针进行取值操作value := *ptr// 取值后的类型fmt.Printf("value type: %T\n", value)// 指针取值后就是指向变量的值fmt.Printf("value: %s\n", value)
}
取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值
package main
import "fmt"
func swap(a, b *int) {fmt.Println(a)fmt.Println(b)*b, *a = *a, *b
}
func main() {x, y := 1, 2swap(&x, &y)fmt.Println(x, y)
}输出:
2,1
package main
import "fmt"
func swap(a, b *int) {b, a = a, b
}
func main() {x, y := 1, 2swap(&x, &y)fmt.Println(x, y)
}输出1,2
Go语言内置的 flag 包实现了对命令行参数的解析,flag 包使得开发命令行工具更为简单
下面的代码通过提前定义一些命令行指令和对应的变量,并在运行时输入对应的参数,经过 flag 包的解析后即可获取命令行的数据
package main
// 导入系统包
import ("flag""fmt"
)
// 定义命令行参数
var mode = flag.String("mode", "", "process mode")
func main() {// 解析命令行参数fmt.Printf("%T\n", mode)flag.Parse()// 输出命令行参数fmt.Println(*mode)
}
将这段代码命名为 main.go,然后使用如下命令行运行: go run main.go --mode=fast 命令行输出结果如下:
fast
代码说明如下:
flag定义的都是指针类型的变量
第 10 行,通过 flag.String,定义一个 mode 变量,这个变量的类型是 *string。后面 3 个参数分别如下:
参数名称:在命令行输入参数时,使用这个名称。
参数值的默认值:与 flag 所使用的函数创建变量类型对应,String 对应字符串、Int 对应整型、Bool 对应布尔型等。
参数说明:使用 -help 时,会出现在说明中。
第 15 行,解析命令行参数,并将结果写入到变量 mode 中。
第 18 行,打印 mode 指针所指向的变量。
new(类型)package main
import "fmt"
func main() {a := new(string)fmt.Printf("%T\n", a) //创建了一个指针类型*a = "今天天气不错"fmt.Println(*a)
}输出:
*string
今天天气不错
全局变量:它的生命周期和整个程序的运行周期是一致的;
局部变量:它的生命周期则是动态的,从创建这个变量的声明语句开始,到这个变量不再被引用为止;
形式参数和函数返回值:它们都属于局部变量,在函数被调用的时候创建,函数调用结束后被销毁。
堆(heap):堆是用于存放进程执行中被动态分配的内存段。它的大小并不固定,可动态扩张或缩减。当进程调用 malloc 等函数分配内存时,新分配的内存就被动态加入到堆上(堆被扩张)。当利用 free 等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减);
栈(stack):栈又称堆栈, 用来存放程序暂时创建的局部变量,也就是我们函数的大括号{ }中定义的局部变量。
var global *int
func f() {var x intx = 1global = &x
}
func g() {y := new(int)*y = 1
}
Go语言中的常量使用关键字 const
定义,用于存储不会改变的数据,常量是在编译时被创建的,即使定义在函数内部也是如此,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。由于编译时的限制,定义常量的表达式必须为能被编译器求值的常量表达式
在Go语言中,你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
常量的值必须是能够在编译时就能够确定的,可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。
如果是批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式,对应的常量类型也是一样的。例如:
const (a = 1bc = 2d
)
fmt.Println(a, b, c, d) // "1 1 2 2"
常量生成器
常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量
package main
import "fmt"
func main() {type Weekday intconst (Sunday Weekday = iotaMondayTuesdayWednesdayThursdayFridaySaturday)fmt.Println(Sunday)fmt.Println(Monday)fmt.Println(Tuesday)fmt.Println(Wednesday)fmt.Println(Thursday)fmt.Println(Friday)fmt.Println(Saturday)
}输出:
0
1
2
3
4
5
6
Go语言的词法元素包括 5
种,分别是标识符(identifier)、关键字(keyword)、操作符(operator)、分隔符(delimiter)、字面量(literal),它们是组成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 |
PS:坑爹的表格真难用,该优化了啊!
标识符是指Go语言对各种变量、方法、函数等命名时使用的字符序列,标识符由若干个字母、下划线_
、和数字组成,且第一个字符必须是字母
标识符的命名需要遵守以下规则:
命名标识符时还需要注意以下几点:
在Go语言中还存在着一些特殊的标识符,叫做预定义标识符,如下表所示:
预定义标识符一共有 36 个,主要包含Go语言中的基础数据类型和内置函数,这些预定义标识符也不可以当做标识符来使用。
Go语言运算符优先级和结合性一览表**
package main
import ("fmt""strconv"
)
func main() {value1, err1 := strconv.Atoi("哈哈") // Ascii To Intfmt.Println(value1)fmt.Println(err1)var x = 4value2 := strconv.Itoa(x) // 数字转字符串是不会出errfmt.Println(value2)}