前言
本章节开始,通过不断实践和试错来对GO语言加快学习、加深了解;为了便于时间和试错,我们先来学习如何在GO语言中编写测试程序:
1. 源码文件以_test结尾:xxx_test.go
2. 测试方法名以Test开头:func TestXXX(t testing.T){ ... }
package try_test
import "testing"
func TestForTyrTest(t *testing.T) {
t.Log("Hi Go try test")
}
保存(ctrl+s)后,将自动于控制台(Output)输出:
=== RUN TestForTyrTest
TestForTyrTest: try_test.go:6: Hi Go try test
--- PASS: TestForTyrTest (0.00s)
PASS
备注:IDE使用的Atom,需先安装go-plus插件:
确认安装了go-plus插件
Atom->preferences->packages
搜索找到go-plus
在settings中,Test配置中选中 Run with verbose flag setting
如果在命令行里运行测试文件,需要执行命令,才能输出 t.Log 里的文字:
go test -v xxx_test.go
变量
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
变量声明
对于变量声明,典型的有两种:
- 使用 var 关键字声明:
var name = xxxxxx
其中,“xxxxxx”既可以是个数值,也可以是表达式执行后的返回结果;可以给name赋值整形、浮点数及字符串等。
var name = "zhangsan"
var age = 28
- 使用短变量声明:
name := "zhangsan"
age := 28
这两种方式各有千秋,有着各自的特点和适用场景。前者可以被用在任何地方,而后者只能被用在函数或者其他更小的代码块中。
在这里,你可能会有个错觉,认为GO语言是弱类型语言;
其实不是的,变量的初始化时省略变量的类型而由系统自动推断,也就是Go 语言中的类型推断功能;类型推断是一种编程语言在编译期自动解释表达式类型的能力。
Go 语言是静态类型的,所以一旦在初始化变量时确定了它的类型,之后就不可能再改变。这就避免了在后面维护程序时的一些问题。
Go 语言的类型推断可以明显提升程序的灵活性,使得代码重构变得更加容易,同时又不会给代码的维护带来额外负担(实际上,它恰恰可以避免散弹式的代码修改),更不会损失程序的运行效率。
变量赋值
- 赋值时可以进行自动类型推断
- 在一个赋值语句中可以对多个变量进行同时赋值
a, b, c := 5, 7, "abc" //一个赋值语句中对多个变量进行赋值
/*交换两个变量的值*/
func TestExChange(t *testing.T){
/*
//常规写法:
a := 1
b := 2
tmp := a
a = b
b = tmp
t.Log(a,b)
*/
//改进写法
a := 1
b := 2
a, b = b, a //一个赋值语句中对多个变量进行赋值
t.Log(a,b)
}
常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量的声明:
const c_name1, c_name2 = value1, value2
package try_test
import "testing"
/// 测试常量一般声明
func TestNormalConstant(t *testing.T) {
//!普通常量定义
const LENGTH = 256
//!多重赋值
const i, b, str = 28, false, "string"
t.Log("LENGTH = ", LENGTH, ";i = ", i, ";b = ", b, ";str = ", str)
/*
=== RUN TestNormalConstant
TestNormalConstant: try_test.go:12: LENGTH = 256 ;i = 28 ;b = false ;str = string
--- PASS: TestNormalConstant (0.00s)
*/
}
///测试常量作为枚举使用
func TestConstantUseOfEnum(t *testing.T) {
//!作为枚举使用
const (
Jan = iota + 1
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
)
t.Log("Jan =", Jan, "; Feb =", Feb, "; Mar =", Mar, "...", "Dec = ", Dec)
/*
=== RUN TestConstantUseOfEnum
TestConstantUseOfEnum: try_test.go:33: Jan = 1 ; Feb = 2 ; Mar = 3 ... Dec = 12
--- PASS: TestConstantUseOfEnum (0.00s)
*/
}
///测试常量作为连续位使用
func TestConstUseOfBinary(t *testing.T) {
//!二进制位表示可读,可写,可执行
const (
Readable = 1 << iota
Writable
Excutable
)
t.Log("Readable = ", Readable, ";Writeable = ", Writable, ";Excutable = ", Excutable)
/*
=== RUN TestConstUseOfBinary
TestConstUseOfBinary: try_test.go:45: Readable = 1 ;Writeable = 2 ;Excutable = 4
--- PASS: TestConstUseOfBinary (0.00s)
*/
}
其中,iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
数据类型
- GO语言不支持隐式类型转换;
- 别名和原有类型也不能进行隐式类型转换;
符号 | 描述 |
---|---|
bool | 布尔值 |
string | 字符串 |
int int8 int16 int32 int64 | 有符号整形 |
uint uint8 uint16 uint32 uint64 | 无符号整形 |
uintptr | 无符号整型,用于存放一个指针 |
byte | 类似 uint8 |
rune | 类似 int32 ,represent a Unicode code point |
float32 float64 | 32/64位浮点型数 |
complex64 complex128 | 32/64 位实数和虚数 |
Go 语言支持指针,但不支持指针运算
package type_test
import "testing"
/// 类型的预定义值(math的package中可找到这些值)
//! math.MaxInt64
//! math.MaxFloat64
//! math.MaxUint32
/// string 是值类型,其默认的初始化值为空字符串,而不是nil
func TestPoint(t *testing.T) {
var arry = [5]int{1, 2, 3, 4, 5}
ptr := &arry[1]
t.Log(*ptr)
t.Logf("%T %T", arry[1], ptr)
/*
=== RUN TestPoint
TestPoint: type_test.go:14: 2
TestPoint: type_test.go:15: int *int
--- PASS: TestPoint (0.00s)
*/
//ptr += 1 //报错:invalid operation: ptr += 1 (mismatched types *int and int)
}
运算符
算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B输出结果 30 |
- | 相减 | A - B 输出结果 -10 |
* | 相乘 | A * B 输出结果 200 |
/ | 相除 | B / A 输出结果 2 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
-- | 自减 | A-- 输出结果 9 |
GO语言没有前置的++,--
比较运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
用==比较数组
在很多主流语言中,数组是个引用类型,不是值类型;所以在相比较的时候是比较数组的引用而不是里面的值;
这点在GO上是完全不同的:
- 相同维数且含有相同个数元素的数组才可以进行比较
- 每个元素都相同才相等
逻辑运算符
下表列出了所有Go语言的逻辑运算符。假定 A 值为 True,B 值为 False
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A ||B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A && B) 为 True |
位运算符
&、|、^、<<、>>与主流编程语言没有区别
&^:按位置零
1 &^ 0 --- 1
1 &^ 1 --- 0
0 &^ 1 --- 0
0 &^ 0 --- 0
如果右边的操作数位上为1,不管左边操作数为多少,结果都为0
如果右边的操作数位上为0,那么其左边操作数为什么,结果就是什么
const (
Readable = 1< true, true, true
a = a&^Excutable //去掉可执行权限
t.Log(a&Readable == Readable, a&Writable == Writable, a&Excutable == Excutable)
// ---> true, true, false
}
运算符优先级
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。
下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + - | ^ |
3 | == != < <= > >= |
2 | && |
1 | || |
条件和循环
循环
GO仅支持循环关键字for
for i:=0; i<5; i++ {
}
///代码示例
package main
import "fmt"
/*while 条件循环*/
//while(n<5)
n := 5
for n<5 {
n++
fmt.Print(n)
}
/*while 无限循环*/
///while(true)
for true {
fmt.Printf("这是无限循环。\n");
}
条件语句
if 语句:
- condition表达式结果必须为布尔值
- 支持变量赋值
if var declaration; condition {
//code to be executed if condition is true
}
package condition_test
import "testing"
func TestIfMultiSec(t *testing.T) {
if a:=1 == 1; a {
t.Log("1==1") /// 输出:1==1
}
}
由于Go方法支持多返回值,因此特性为编程带来了便捷;在后面的学习章节中在详细介绍,这里先简单抛出个例子:
package condition_test
import "testing"
func TestIfMultiSec(t *testing.T) {
if ret, err:=function; err==nil {
......
}else{
......
}
}
switch语句:
- 条件表达式不限制为常量或者表达式
- 单个case中,可以出现多个结果选项,使用逗号分隔
- 与C语言等规则相反,Go语言不需要用break来明确退出一个case
- 可以不设定switch之后的条件表达式,在这种情况下,整个switch结构与多个if ... else ... 的逻辑作用相同
代码示例1:
package condition_test
func TestSwitchMultiCase(t *testing.T) {
for i :=0; i<5; i++ {
switch i {
case 0,2:
t.Log("Event")
case 1,3:
t.Log("Odd")
default:
t.Log("it is not 0-3")
}
}
}
代码示例2:
package condition_test
func TestSwitchMultiCase(t *testing.T) {
for i :=0; i<5; i++ {
switch {
case i%2==0:
t.Log("Event")
case i%2==1:
t.Log("Odd")
default:
t.Log("it is not 0-3")
}
}
}