本文最后更新于 1021 天前,其中的信息可能已经有所发展或是发生改变。
近段时间,本人开始无基础入门 Go 语言,既是为毕设打基础,更是为日后的社会工作做准备。
由此,不定期更新近期学习中的收获,供学习交流用。
本篇中,将简单介绍 Go 语言最基础的知识:变量与常量,数据类型,运算符,条件和循环。
Hello world!
不解释,直接放出代码:
package main
import "fmt"
func main() {
	fmt.Println("Hello world!")
}
变量与常量
变量
Go 中的变量需要声明以后才能且必须使用,同一作用域内不支持重复声明。
常用的声明变量方式:
//var indertifer type
var age int    //int类型的变量不赋值,默认值是0
var price float64 = 5 //声明变量为64位浮点,且赋值5
var flag bool  //默认值是false
var (
	a int = 1
	b int = 1
)
可以同时声明多个变量:
var x, y int
var a, b = 24, "years"
特别的,Go 支持类型推断:
var title = “Tempest”
var count = 10
短变量只能在函数内部进行声明,使用 := 运算符对变量进行声明和初始化。
mystr := "hello world"
特别注意,在以下代码中:
        mystr := "hello world"
        mystr := "hello"
    会出现编译错误。:=仅用于对变量的声明,而同一个变量名不能声明两次。
    故第二行的:=不符合规范,应使用=符号进行赋值操作。
    *若使用:=声明多个变量,则仅需其中至少一个为新变量即可,如:
        mystr,anostr := "hello","world"
    则不会报编译错误,因为anostr为新变量声明。但你不能通过此方法改变mystr的变量类型。
:= 不能被用在函数体外,也就是说,当你打算声明一个全局变量时,你只能使用var。
如果我们接收到多个变量,有一些变量使用不到,可以使用下划线作为变量名,这种变量叫做匿名变量。
func GetInteger() (int, int) {
	return 1, 2
}
x, _ := GetInteger()
_, y := GetInteger()
fmt.Println(a, b)	//输出结果为 1 2
常量
定义一个常量使用 const,语法如下:
//const constantName [type] = value
const PI float32 = 3.14
const H = 100
const (
	a int = 1
	b = 2
	c	//如不指定类型和初始化值,则与上一行非空常量右值相同
)
iota是go语言的常量计数器,只能在常量表达式中使用。
iota在const关键字出现时将被重置为0,const中每新增一行常量声明将使iota计数一次。
const (
	a = iota //0 
	b = iota //1
	c = iota //2
)
const (		//iota中间截断
	d = iota //0 
	e = 114514
	f = iota //2
)
const (
	g = iota //0
	_        //1
	h = iota //2
)
数据类型
基本数据类型如下:
- 整型
- 有符号:
int8 int16 int32 int64rune是int32的别名类型。int16对应 C 语言中的short型 ,int64对应 C 语言中的long型。int自动匹配所用的操作系统,系统是 32 位就是int32,系统是 64 位就是int64。
 - 无符号:
uint8 uint16 uint32 uint64byte是uint8的别名类型。
 
 - 有符号:
 - 浮点型(遵循 
IEEE 754标准)float32最大范围为3.4e38,用常量math.MaxFloat32float64最大范围为1.8e308,用常量math.MaxFloat64
 - 复数
complex64实部和虚部分别是 32 位complex128实部和虚部分别是 64 位
 - 布尔值
bool:只有true和false
 - 字符串
string内部实现使用 UTF-8 编码- 多行字符串,用反引号(“)。
反引号间换行认为字符串中的换行;但是反引号间所有的转义字符均无效。 
- 多行字符串,用反引号(“)。
 
 
运算符
Go 的基础运算符如下:
首先定义:
var (
	a,b,c int = 10,20,5	//1010,10100,101
	d,e bool = true,false
)
则相应的运算符与结果如下:
算术运算符
| 算术运算符 | 描述 | 运算结果 | 
| + | 相加 | a + b 结果为 30 | 
| – | 相减 | a – b 结果为 -10 | 
| * | 相乘 | a * b 结果为 200 | 
| / | 相除 | b / a 结果为 2 | 
| % | 取余 | a % b 结果为 10 | 
| ++ | 自增 | a++ 结果为 11 | 
| — | 自减 | b– 结果为 19 | 
++a,--b)赋值运算符
| 赋值运算符 | 描述 | 运算结果 | 
| = | 将一个表达式的值赋给一个左值 | c = a + b,c 为 30 | 
| += | 相加后赋值 | c += a,c 为 15 | 
| -= | 相减后赋值 | c -= b,c 为 -15 | 
| *= | 相乘后赋值 | c *= a,c 为 50 | 
| /= | 相除后赋值 | b /= a,b 为 2 | 
| %= | 左移后赋值 | a %= c,a 为 0 | 
| <<= | 左移后赋值 | a <<= c,a 为 320 | 
关系运算符
| 关系运算符 | 描述 | 运算结果 | 
| == | 检查是否相等 | a == b 为 false | 
| != | 检查是否不相等 | a != b 为 true | 
| > | 检查左值是否大于右值 | a > b 为 false | 
| < | 检查左值是否校于右值 | a < b 为 true | 
| >= | 检查左值是否大于等于右值 | a >= b 为 false | 
| <= | 检查左值是否小于等于右值 | a <= b 为 true | 
逻辑运算符
| 逻辑运算符 | 描述 | 运算结果 | 
| && | 逻辑 AND | d && e 为 false | 
| || | 逻辑 OR | d || e 为 true | 
| ! | 逻辑 NOT | !e 为 true | 
位运算符
| 位运算符 | 描述 | 运算结果 | 
| & | 二进制各位相与 | a & b 为 0 | 
| | | 二进制各位相或 | a | b 为 30 | 
| ^ | 二进制各位相异或 | a ^ b 为 30 | 
| << | 左移运算 | a << 2 为 40 | 
| >> | 右移运算 | b >> 2 为 5 | 
| &^ | 按位清零 | a &^ b 为 10 | 
其他运算符
| 运算符 | 描述 | 运算结果 | 
| & | 对变量取地址 | &a 返回变量的实际内存地址 | 
| * | 对地址取值 | *a 返回指针变量对应的数值 | 
下面用一段代码来举例:
package operator_test
import "testing"
func TestComapreArray(t *testing.T) {
	a := [...]int{1, 2, 3, 4}
	b := [...]int{1, 3, 4, 5}
	//c := [...]int{1, 2, 3, 4, 5}
	d := [...]int{1, 2, 3, 4}
	t.Log(a == b)
	//t.Log(a==c)
	t.Log(a == d)
}
const (
	read  int = 4
	write int = 2
	exec  int = 1
)
func TestBitClear(t *testing.T) {
	var a int = 7
	a = a &^ write
	t.Log(a, a&read == read, a&write == write, a&exec == exec)
}
其测试结果如下:
=== RUN   TestComapreArray
    operator_test.go:10: false
    operator_test.go:12: true
--- PASS: TestComapreArray (0.00s)
=== RUN   TestBitClear
    operator_test.go:24: 5 true false true
--- PASS: TestBitClear (0.00s)
PASS
Process finished with the exit code 0
测试结果解析:
- TestComapreArray 函数中,a,b,c,d 为四个数组
- a 与 b 内部数据不同,故其不相等,返回 false
若b := [...]int{1, 3, 2, 4}因其顺序不相同,仍然返回 false - a 与 c 数组长度不相同,若强行进行比对会报编译错误,提示变量类型不同
 - a 与 d 数组长度相同,内部数据也相同,故返回 true
 
 - a 与 b 内部数据不同,故其不相等,返回 false
 - TestBitClear 函数中,模拟了文件读写权限的运算
- 0111 代表可读写,可执行,
var a int = 7对其赋对应值 a = a &^ write,即对其取消写入权限,此时 a=5 ,对应二进制 0101- 最后进行比对,可知 a=5,对应可读可执行不可写,与前面按位清零运算对应
 
 - 0111 代表可读写,可执行,
 
条件和循环
条件
if … else 语句
if 语句遵循如下格式:
if condition1 {
    // do something
} else if condition2 {
    // do something else
} else {
    // catch-all or default
}
switch语句
在 Go 语言中,switch 语句会与其他语言有所不同:
switch语句找到匹配项执行完毕后,默认不需要 break 即跳出语句。switch默认情况下case最后自带break语句,匹配成功后就不会执行其他case,如果我们需要执行后面的case,可以使用fallthrough。switch后面变量的类型可以是任何类型,不再局限于常量或整数。
示例代码如下:
func TestSwitchCondition(t *testing.T) {
	for i := 1; i <= 12; i++ {
		switch i {
		case 1, 3, 5, 7, 9:
			t.Log("odd")
		case 2, 4, 6, 8, 10:
			t.Log("even")
		default:
			t.Log("too high")
		}
	}
}
循环
与 C++ 等其他语言不同,Go 对于循环只有 for 语句,并没有其他语言常用的 while 和 do-while 等。
package loop
import "testing"
func TestWileLoop(t *testing.T) {
	for i := 1; i <= 5; i++ {
		t.Log(i, i%2 == 0)	//从1-5整数顺序输出,并判定是否偶数
	}
}
如上述代码,Go 的 for 语句与其他语言并没有太大不同。其使用遵循以下格式:
for init; condition; post {
	// body
}
	