var name type
其中,var 是声明变量的关键字,name 是变量名,type 是变量的类型
var (
a int
b string
c []float32
d func() bool
e struct {
x int
}
)
名字 := 表达式
i, j := 0, 1
需要注意的是,简短模式(short variable declaration)有以下限制:
定义变量,同时显式初始化。 //相当于赋值,可以不用再声明获取到的变量的类型
不能提供数据类型。 // 因为赋值直接会有类型了,所以不用提供数据类型
只能用在函数内部。 //全局定义还是得用var
示例:
func main() {
x:=100
a,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 = 3
var b int = 4
//声明局部变量 c 并计算 a 和 b 的和
c := a + b
fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
import "fmt"
//声明全局变量
var c int
func main() {
//声明局部变量
var a, b int
//初始化参数
a = 3
b = 4
c = a + b
fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
import (
"fmt"
)
//全局变量 a
var a int = 13
func main() {
//局部变量 a 和 b
var a int = 3
var b int = 4
fmt.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 + b
return 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.34
12.34
12
package main
import "fmt"
func main() {
i := 0
var c float32 = 0.2
b := 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.Buffer
stringBuffer.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类型为*string
ptr := &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, 2
swap(&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, 2
swap(&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 int
x = 1
global = &x
}
func g() {
y := new(int)
*y = 1
}
Go语言中的常量使用关键字 const
定义,用于存储不会改变的数据,常量是在编译时被创建的,即使定义在函数内部也是如此,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。由于编译时的限制,定义常量的表达式必须为能被编译器求值的常量表达式
在Go语言中,你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
常量的值必须是能够在编译时就能够确定的,可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。
如果是批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式,对应的常量类型也是一样的。例如:
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // "1 1 2 2"
常量生成器
常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量
package main
import "fmt"
func main() {
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
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语言中的基础数据类型和内置函数,这些预定义标识符也不可以当做标识符来使用。
package main
import (
"fmt"
"strconv"
)
func main() {
value1, err1 := strconv.Atoi("哈哈") // Ascii To Int
fmt.Println(value1)
fmt.Println(err1)
var x = 4
value2 := strconv.Itoa(x) // 数字转字符串是不会出err
fmt.Println(value2)
}