(3). GO嵌入式开发之 --- 基本程序结构

前言

        本章节开始,通过不断实践和试错来对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 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。

变量声明

对于变量声明,典型的有两种:

  1. 使用 var 关键字声明:
    var name = xxxxxx
    其中,“xxxxxx”既可以是个数值,也可以是表达式执行后的返回结果;可以给name赋值整形、浮点数及字符串等。
var name = "zhangsan"
var age = 28
  1. 使用短变量声明:
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<<iota
  Writable
  Excutable
)

func TestBitClear(t *testing.T){
  a:=7 ///0111
  t.Log(a&Readable == Readable, a&Writable == Writable, a&Excutable == Excutable) 
 // ---> 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 语句:

  1. condition表达式结果必须为布尔值
  2. 支持变量赋值
    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语句:

  1. 条件表达式不限制为常量或者表达式
  2. 单个case中,可以出现多个结果选项,使用逗号分隔
  3. 与C语言等规则相反,Go语言不需要用break来明确退出一个case
  4. 可以不设定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")
         }  
     }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335