一、编写第一个Go程序
1、基本程序结构
package main //包,表名代码所在的模块(包) import "fmt" //引入代码依赖 //功能实现 func main(){ fmt.Println("Hello,World!") }
2、应用程序入口
- 必须是main包 package main
- 必须是main方法 func main()
- 文件名不一定是main.go
3、退出返回值
与其他主要变成语言的差异
- Go中的main函数不支持任何返回值
- 通过os.Exit 来返回状态
4、获取命令行参数
与其他主要变成语言的差异
- main函数不支持传入参数
func main~~(arg []string)~~
- 在程序中直接通过os.Args获取命令行参数
二、变量,常量以及与其他语言的差异
1、编写测试程序
- 源文件以_test结尾:xxx_test.go
- 测试方法以Test开头:func TestXXX(t *testing.T){}
package test import ( "log" "testing" ) func TestFirstTry(T *testing.T){ log.Print("My first try!") }
2、实现Fibonacci数列
1,1,2,3,5,8,13,…
package fib import ( "testing" ) // TestFibList 是测试斐波那契数列生成函数的单元测试函数 func TestFibList(t *testing.T) { var a int = 1 var b int = 1 // 另一种变量声明方式: // var ( // a int = 1 // b = 1 // ) // 或者使用短变量声明方式: // a := 1 // b := 1 // 输出变量 a 的值 t.Log(a) // 循环生成斐波那契数列的前5个数并输出 for i := 0; i < 5; i++ { // 输出变量 b 的值 t.Log(b) // 交换 a 和 b 的值,生成下一个斐波那契数 tmp := a a = b b = tmp + a } }
3、变量赋值
与其他主要变成语言的差异
- 赋值可以进行自动类型推断
- 在一个赋值语句中可以对多个变量进行同时赋值
package fib import ( "testing" ) // TestExChange 是测试变量交换函数的单元测试函数 func TestExChange(t *testing.T) { // 初始化两个变量 a 和 b 的值 a := 1 b := 2 //temp :=a //a=b //b=temp // 使用短变量声明方式,同时交换 a 和 b 的值 // 在 Go 中,可以通过这种方式轻松地实现两个变量的值交换 a, b = b, a // 输出交换后的变量值 t.Log(a, b) }
输出结果:
4、常量定义
与其他主要变成语言的差异
快速设置连续值
iota枚举
Go里面有一个关键字iota
,这个关键字用来声明enum
的时候采用,它默认开始值是0,const
中每增加一行加1:
package constan_test import "testing" // 第一个常量组,使用 iota 枚举星期几 const ( Monday = iota + 1 Tuesday Wednesday ) // 第二个常量组,使用 iota 创建一组表示文件权限的常量 const ( Readable = 1 << iota // 位运算左移,表示可读 Writable // 位运算左移,表示可写 Executable // 位运算左移,表示可执行 ) // TestConstanTry 是测试星期几常量的单元测试函数 func TestConstanTry(t *testing.T) { // 输出星期几的常量值 t.Log("星期一:", Monday) t.Log("星期二:", Tuesday) t.Log("星期三:", Wednesday) } // TestConstanTry1 是测试文件权限常量的单元测试函数 func TestConstanTry1(t *testing.T) { //a:=7 // 二进制表示为 0111 TRUE TRUE TRUE a := 1 // 二进制表示为 0001 true false false // 使用位运算检查文件权限 t.Log("可读:", a&Readable == Readable) t.Log("可写:", a&Writable == Writable) t.Log("可执行:", a&Executable == Executable) }
三、数据类型
数据类型 | 描述 | 示例 |
int | 有符号整数类型,大小取决于计算机架构,常用于表示整数。 | var x int = 10 |
int8 | 有符号8位整数类型,范围为-128到127。 | var x int8 = 127 |
int16 | 有符号16位整数类型,范围为-32768到32767。 | var x int16 = -300 |
int32 | 有符号32位整数类型,范围为-2147483648到2147483647。 | var x int32 = 100000 |
int64 | 有符号64位整数类型,范围为-9223372036854775808到9223372036854775807。 | var x int64 = -9223372036854775808 |
uint | 无符号整数类型,大小取决于计算机架构,常用于表示正整数。 | var x uint = 10 |
uint8 | 无符号8位整数类型,范围为0到255。 | var x uint8 = 255 |
uint16 | 无符号16位整数类型,范围为0到65535。 | var x uint16 = 65535 |
uint32 | 无符号32位整数类型,范围为0到4294967295。 | var x uint32 = 4294967295 |
uint64 | 无符号64位整数类型,范围为0到18446744073709551615。 | var x uint64 = 18446744073709551615 |
float32 | 32位浮点数类型,可表示小数。 | var x float32 = 3.14 |
float64 | 64位浮点数类型,可表示小数。 | var x float64 = 3.14 |
complex64 | 由两个32位浮点数表示的复数类型。 | var x complex64 = 3 + 4i |
complex128 | 由两个64位浮点数表示的复数类型。 | var x complex128 = 3 + 4i |
byte | uint8 的别名,常用于表示ASCII字符。 | var x byte = ‘A’ |
rune | int32 的别名,常用于表示Unicode字符。 | var x rune = ‘你’ |
string | 字符串类型,表示一串字符。 | var x string = “Hello” |
bool | 布尔类型,表示真或假。 | var x bool = true |
array | 数组类型,固定大小的元素序列。 | var x [3]int = [3]int{1, 2, 3} |
slice | 切片类型,可变大小的元素序列。 | var x []int = []int{1, 2, 3} |
map | 映射类型,存储键值对的无序集合。 | var x map[string]int = map[string]int{“a”: 1, “b”: 2} |
struct | 结构体类型,自定义的复合数据类型。 | type Person struct {Name string; Age int} |
1、类型转化
与其他主要变成语言的差异
- Go语言不允许隐式类型转换
- 别名和原有类型也不能进行隐式类型转换
2、类型的预定义值
math 包提供了一些常用类型的预定义值,包括整数、浮点数等。以下是三个例子:
- math.MaxInt64
- math.MaxFloat64
- math.MaxUint32
package math_constants import ( "fmt" "math" ) func ExampleMaxInt64() { // 输出 int64 类型的最大值 fmt.Printf("int64 类型的最大值:%d\n", math.MaxInt64) } func ExampleMaxFloat64() { // 输出 float64 类型的最大值 fmt.Printf("float64 类型的最大值:%f\n", math.MaxFloat64) } func ExampleMaxUint32() { // 输出 uint32 类型的最大值 fmt.Printf("uint32 类型的最大值:%d\n", math.MaxUint32) } func main() { ExampleMaxInt64() ExampleMaxFloat64() ExampleMaxUint32() }
这些预定义值对于处理数值边界和范围非常有用。
3、指针类型
与其他主要变成语言的差异
- 不支持指针运算
在 Go 语言中,指针的使用受到一些限制,其中最明显的一点是不支持指针运算。以下是一个简单的例子,说明了指针运算在 Go 中是不允许的:
package pointer_test import "testing" // TestPointerArithmetic 是测试指针运算的单元测试函数 func TestPointerArithmetic(t *testing.T) { // 定义一个整数变量 x,并赋值为 10 x := 10 // 定义一个指向整数的指针变量 p,指向 x 的内存地址 p := &x // 尝试进行指针运算(不允许的操作),这将导致编译错误 // p = p + 1 // 这行代码会导致编译错误 // 输出 x 的值和指针变量 p 的值 t.Logf("x 的值:%d,指针变量 p 的值:%p", x, p) }
在这个例子中,尝试进行指针运算 p = p + 1 会导致编译错误,因为在 Go 中不允许直接对指针进行加法或减法运算。
- string是值类型,其默认的初始化值为空字符串,而不是null
在 Go 中,string 是一种特殊的值类型,它代表不可变的字符序列。string 的默认初始化值是空字符串而不是 null。以下是一个示例:
package string_test import "testing" // TestStringInitialization 是测试 string 初始化的单元测试函数 func TestStringInitialization(t *testing.T) { // 声明一个字符串变量 s,其默认初始化值为空字符串 var s string // 输出字符串变量 s 的值 t.Logf("字符串变量 s 的值:%q", s) }
在这个例子中,s 是一个字符串变量,由于没有显式赋值,它的默认初始化值是空字符串。通过 %q 格式化符输出字符串时,如果字符串为空,会显示为空字符串而不是 null。
四、运算符
1、算数运算符
运算符 | 描述 | 示例 |
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 求余 | a % b |
++ | 自增 | a++ 或 ++a |
– | 自减 | a– 或 –a |
Go语言没有前置的++,–(++a)
以下是一个使用算术运算符的简单示例:
package arithmetic_operators import "fmt" func main() { // 定义两个整数变量 a := 10 b := 5 // 加法 sum := a + b fmt.Printf("加法结果:%d\n", sum) // 减法 difference := a - b fmt.Printf("减法结果:%d\n", difference) // 乘法 product := a * b fmt.Printf("乘法结果:%d\n", product) // 除法 quotient := a / b fmt.Printf("除法结果:%d\n", quotient) // 求余 remainder := a % b fmt.Printf("求余结果:%d\n", remainder) // 自增 a++ fmt.Printf("自增后的值:%d\n", a) // 自减 b-- fmt.Printf("自减后的值:%d\n", b) }
2、比较运算符
运算符 | 描述 | 示例 |
== | 相等 | a == b |
!= | 不相等 | a != b |
< | 小于 | a < b |
> | 大于 | a > b |
<= | 小于等于 | a <= b |
>= | 大于等于 | a >= b |
package comparison_operators import "fmt" func main() { // 定义两个整数变量 a := 10 b := 5 // 相等 equal := a == b fmt.Printf("相等:%t\n", equal) // 不相等 notEqual := a != b fmt.Printf("不相等:%t\n", notEqual) // 小于 lessThan := a < b fmt.Printf("小于:%t\n", lessThan) // 大于 greaterThan := a > b fmt.Printf("大于:%t\n", greaterThan) // 小于等于 lessThanOrEqual := a <= b fmt.Printf("小于等于:%t\n", lessThanOrEqual) // 大于等于 greaterThanOrEqual := a >= b fmt.Printf("大于等于:%t\n", greaterThanOrEqual) }
3、用==比较数组
- 数组的维数必须相同。
- 数组中元素的个数必须相同。
- 数组中的每个元素都必须相等。
package test import ( "fmt" "testing" ) func TestArrayComparison(t *testing.T) { // 定义两个数组 array1 := [3]int{1, 2, 3} array2 := [3]int{1, 2, 3} array3 := [3]int{4, 5, 6} // 使用 == 比较数组 equal1 := array1 == array2 equal2 := array1 == array3 // 输出比较结果 fmt.Printf("array1 是否等于 array2:%t\n", equal1) fmt.Printf("array1 是否等于 array3:%t\n", equal2) }
4、逻辑运算符
运算符 | 描述 | 示例 |
&& | 逻辑与 | a && b |
|| | 逻辑或 | a || b |
! | 逻辑非 | !a |
func TestLogical(t *testing.T) { // 定义两个布尔变量 isTrue := true isFalse := false // 逻辑与 andResult := isTrue && isFalse fmt.Printf("逻辑与结果:%t\n", andResult) // 逻辑或 orResult := isTrue || isFalse fmt.Printf("逻辑或结果:%t\n", orResult) // 逻辑非 notResult := !isTrue fmt.Printf("逻辑非结果:%t\n", notResult) }
5、位运算符
运算符 | 描述 | 示例 |
& | 位与 | a & b |
| | 位或 | a | b |
^ | 位异或 | a ^ b |
<< | 左移 | a << b |
>> | 右移 | a >> b |
&^ | 位清空 (AND NOT) | a &^ b |
func TestBitwiseOperators(t *testing.T) { // 定义两个整数变量 a := 5 // 二进制: 0101 b := 3 // 二进制: 0011 // 位与 andResult := a & b fmt.Printf("位与结果:%d\n", andResult) // 0001 (1) // 位或 orResult := a | b fmt.Printf("位或结果:%d\n", orResult) // 0111 (7) // 位异或 xorResult := a ^ b fmt.Printf("位异或结果:%d\n", xorResult) // 0110 (6) // 左移 leftShiftResult := a << 1 fmt.Printf("左移结果:%d\n", leftShiftResult) // 1010 (10) // 右移 rightShiftResult := a >> 1 fmt.Printf("右移结果:%d\n", rightShiftResult) // 0010 (2) // 位清空 (AND NOT) clearResult := a &^ b fmt.Printf("位清空结果:%d\n", clearResult) // 0100 (4) }
与其他主要变成语言的差异
- ** **&^按位置零
该操作符的使用方式是 a &^ b,它的作用是将 b 中为 1 的位在 a 中对应位置上清零。
func TestBitwiseClear(t *testing.T) { // 定义两个整数变量 a := 5 // 二进制: 0101 b := 3 // 二进制: 0011 // 使用 &^ 按位清零 result := a &^ b // 输出结果 fmt.Printf("a &^ b 按位清零结果:%d\n", result) // 0100 (4) }
五、循环
与其他主要变成语言的差异
GO语言仅支持循环关键字for
1. 基本的 for 循环:
// 基本的 for 循环 for i := 1; i <= 5; i++ { fmt.Println(i) }
2. for range 循环:
func TestFor(t *testing.T) { // 使用 for range 遍历数组 numbers := []int{1, 2, 3, 4, 5} for index, value := range numbers { fmt.Printf("索引:%d,值:%d\n", index, value) } // 使用 for range 遍历字符串 message := "Hello, Go!" for index, char := range message { fmt.Printf("索引:%d,字符:%c\n", index, char) } }
3. while 条件循环:
func TestFor01(t *testing.T) { // 模拟 while 循环 counter := 1 for counter <= 5 { fmt.Println(counter) counter++ } }
4. 无限循环:
func TestFor02(t *testing.T) { // 无限循环 counter := 0 for { fmt.Println("无限循环") counter++ if counter == 3 { break // 终止循环 } } }
5.if条件
1. 基本的 if 语句:
// 基本的 if 语句 x := 10 if x > 5 { fmt.Println("x 大于 5") } else { fmt.Println("x 不大于 5") }
2. if 语句的条件可以包含初始化语句:
// if 语句的条件包含初始化语句 if x := 10; x > 5 { fmt.Println("x 大于 5") } else { fmt.Println("x 不大于 5") }
在这个例子中,if 语句的条件部分包含了初始化语句 x := 10,这个变量 x 只在 if 语句的作用域内有效。
3.多个 if 语句的嵌套
// 多个 if 语句的嵌套 x := 10 if x > 5 { fmt.Println("x 大于 5") if x > 8 { fmt.Println("x 大于 8") } } else { fmt.Println("x 不大于 5") }
与其他主要变成语言的差异
- condition 表达式结果必须为布尔值
在 Go 语言中,条件表达式的结果必须是一个布尔值。这意味着 if 和 for 等语句中的条件表达式必须评估为布尔类型,不能接受非布尔类型的值
// Go 语言中的条件表达式必须是布尔值 if x > 5 { // ... } // 错误示例,编译时将会报错 if x { // ... }
在上述错误示例中,x 是一个变量,但它的类型不是布尔类型,因此这个条件表达式会导致编译错误。相比之下,一些其他语言可能允许使用非布尔类型的值作为条件。
- 支持变量赋值
6.switch条件
与其他主要变成语言的差异
1.条件表达式不限制为常量或者整数;
func TestSwitch(t *testing.T) { var x interface{} = "hello" switch x.(type) { case int: fmt.Println("x 是一个整数") case string: fmt.Println("x 是一个字符串") default: fmt.Println("未知类型") } }
switch 语句的条件表达式可以是任意类型,不限制为常量或整数。这使得 switch 可以用于更复杂的条件判断,例如字符串、接口等类型。
2.单个 case 中,可以出现多个结果选项,使用逗号分隔;
func TestSwitch2(t *testing.T) { num := 2 switch num { case 1, 2: fmt.Println("数字是1或2") case 3: fmt.Println("数字是3") default: fmt.Println("未知数字") } }
3.与C语言等规则相反,Go 语言不需要用break来明确退出一个 case;
func TestSwitch3(t *testing.T) { day := "Monday" switch day { case "Monday": fmt.Println("星期一") case "Tuesday": fmt.Println("星期二") default: fmt.Println("其他日子") } }
4.可以不设定switch 之后的条件表达式,在此种情况下,整个 switch 结构与多个 if…else…的逻辑作用等同
func TestSwitch4(t *testing.T) { num := 2 switch { case num > 5: fmt.Println("数字大于5") case num > 0: fmt.Println("数字大于0") default: fmt.Println("未知数字") } }