(3). GO嵌入式開(kāi)發(fā)之 --- 基本程序結(jié)構(gòu)

前言

? ? ? ? 本章節(jié)開(kāi)始,通過(guò)不斷實(shí)踐和試錯(cuò)來(lái)對(duì)GO語(yǔ)言加快學(xué)習(xí)、加深了解;為了便于時(shí)間和試錯(cuò),我們先來(lái)學(xué)習(xí)如何在GO語(yǔ)言中編寫(xiě)測(cè)試程序:

1. 源碼文件以_test結(jié)尾:xxx_test.go
2. 測(cè)試方法名以Test開(kāi)頭:func TestXXX(t testing.T){ ... }

package try_test

import "testing"

func TestForTyrTest(t *testing.T) {
    t.Log("Hi Go try test")
}

保存(ctrl+s)后,將自動(dòng)于控制臺(tái)(Output)輸出:

=== RUN TestForTyrTest 
TestForTyrTest: try_test.go:6: Hi Go try test 
--- PASS: TestForTyrTest (0.00s) 
PASS

備注:IDE使用的Atom,需先安裝go-plus插件:
確認(rèn)安裝了go-plus插件
Atom->preferences->packages
搜索找到go-plus
在settings中,Test配置中選中 Run with verbose flag setting

如果在命令行里運(yùn)行測(cè)試文件,需要執(zhí)行命令,才能輸出 t.Log 里的文字:
go test -v xxx_test.go

變量

Go 語(yǔ)言變量名由字母、數(shù)字、下劃線組成,其中首個(gè)字符不能為數(shù)字。

變量聲明

對(duì)于變量聲明,典型的有兩種:

  1. 使用 var 關(guān)鍵字聲明:
    var name = xxxxxx
    其中,“xxxxxx”既可以是個(gè)數(shù)值,也可以是表達(dá)式執(zhí)行后的返回結(jié)果;可以給name賦值整形、浮點(diǎn)數(shù)及字符串等。
var name = "zhangsan"
var age = 28
  1. 使用短變量聲明:
name := "zhangsan"
age := 28

這兩種方式各有千秋,有著各自的特點(diǎn)和適用場(chǎng)景。前者可以被用在任何地方,而后者只能被用在函數(shù)或者其他更小的代碼塊中。

在這里,你可能會(huì)有個(gè)錯(cuò)覺(jué),認(rèn)為GO語(yǔ)言是弱類型語(yǔ)言;
其實(shí)不是的,變量的初始化時(shí)省略變量的類型而由系統(tǒng)自動(dòng)推斷,也就是Go 語(yǔ)言中的類型推斷功能;類型推斷是一種編程語(yǔ)言在編譯期自動(dòng)解釋表達(dá)式類型的能力。

Go 語(yǔ)言是靜態(tài)類型的,所以一旦在初始化變量時(shí)確定了它的類型,之后就不可能再改變。這就避免了在后面維護(hù)程序時(shí)的一些問(wèn)題。

Go 語(yǔ)言的類型推斷可以明顯提升程序的靈活性,使得代碼重構(gòu)變得更加容易,同時(shí)又不會(huì)給代碼的維護(hù)帶來(lái)額外負(fù)擔(dān)(實(shí)際上,它恰恰可以避免散彈式的代碼修改),更不會(huì)損失程序的運(yùn)行效率。

變量賦值
  • 賦值時(shí)可以進(jìn)行自動(dòng)類型推斷
  • 在一個(gè)賦值語(yǔ)句中可以對(duì)多個(gè)變量進(jìn)行同時(shí)賦值
a, b, c := 5, 7, "abc"  //一個(gè)賦值語(yǔ)句中對(duì)多個(gè)變量進(jìn)行賦值

/*交換兩個(gè)變量的值*/
func TestExChange(t *testing.T){
/*
    //常規(guī)寫(xiě)法:
    a := 1
    b := 2
    tmp := a
    a = b
    b = tmp
    t.Log(a,b)
*/

   //改進(jìn)寫(xiě)法
    a := 1
    b := 2
    a, b = b, a //一個(gè)賦值語(yǔ)句中對(duì)多個(gè)變量進(jìn)行賦值
    t.Log(a,b)
}

常量

常量是一個(gè)簡(jiǎn)單值的標(biāo)識(shí)符,在程序運(yùn)行時(shí),不會(huì)被修改的量。
常量的聲明:
const c_name1, c_name2 = value1, value2

package try_test

import "testing"

/// 測(cè)試常量一般聲明
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)   
   */
}

///測(cè)試常量作為枚舉使用
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)
   */
}

///測(cè)試常量作為連續(xù)位使用
func TestConstUseOfBinary(t *testing.T) {
    //!二進(jìn)制位表示可讀,可寫(xiě),可執(zhí)行
    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,特殊常量,可以認(rèn)為是一個(gè)可以被編譯器修改的常量。
iota 在 const關(guān)鍵字出現(xiàn)時(shí)將被重置為 0(const 內(nèi)部的第一行之前),const 中每新增一行常量聲明將使 iota 計(jì)數(shù)一次(iota 可理解為 const 語(yǔ)句塊中的行索引)。

數(shù)據(jù)類型

  • GO語(yǔ)言不支持隱式類型轉(zhuǎn)換;
  • 別名和原有類型也不能進(jìn)行隱式類型轉(zhuǎn)換;
符號(hào) 描述
bool 布爾值
string 字符串
int int8 int16 int32 int64 有符號(hào)整形
uint uint8 uint16 uint32 uint64 無(wú)符號(hào)整形
uintptr 無(wú)符號(hào)整型,用于存放一個(gè)指針
byte 類似 uint8
rune 類似 int32 ,represent a Unicode code point
float32 float64 32/64位浮點(diǎn)型數(shù)
complex64 complex128 32/64 位實(shí)數(shù)和虛數(shù)
Go 語(yǔ)言支持指針,但不支持指針運(yùn)算
package type_test

import "testing"

/// 類型的預(yù)定義值(math的package中可找到這些值)
//! math.MaxInt64
//! math.MaxFloat64
//! math.MaxUint32

/// string 是值類型,其默認(rèn)的初始化值為空字符串,而不是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 //報(bào)錯(cuò):invalid operation: ptr += 1 (mismatched types *int and int)
}


運(yùn)算符

算術(shù)運(yùn)算符
運(yùn)算符 描述 實(shí)例
+ 相加 A + B輸出結(jié)果 30
- 相減 A - B 輸出結(jié)果 -10
* 相乘 A * B 輸出結(jié)果 200
/ 相除 B / A 輸出結(jié)果 2
% 求余 B % A 輸出結(jié)果 0
++ 自增 A++ 輸出結(jié)果 11
-- 自減 A-- 輸出結(jié)果 9

GO語(yǔ)言沒(méi)有前置的++,--

比較運(yùn)算符
運(yùn)算符 描述 實(shí)例
== 檢查兩個(gè)值是否相等,如果相等返回 True 否則返回 False。 (A == B) 為 False
!= 檢查兩個(gè)值是否不相等,如果不相等返回 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

用==比較數(shù)組
在很多主流語(yǔ)言中,數(shù)組是個(gè)引用類型,不是值類型;所以在相比較的時(shí)候是比較數(shù)組的引用而不是里面的值;
這點(diǎn)在GO上是完全不同的:

  • 相同維數(shù)且含有相同個(gè)數(shù)元素的數(shù)組才可以進(jìn)行比較
  • 每個(gè)元素都相同才相等
邏輯運(yùn)算符

下表列出了所有Go語(yǔ)言的邏輯運(yùn)算符。假定 A 值為 True,B 值為 False

運(yùn)算符 描述 實(shí)例
&& 邏輯 AND 運(yùn)算符。 如果兩邊的操作數(shù)都是 True,則條件 True,否則為 False。 (A && B) 為 False
|| 邏輯 OR 運(yùn)算符。 如果兩邊的操作數(shù)有一個(gè) True,則條件 True,否則為 False。 (A ||B) 為 True
! 邏輯 NOT 運(yùn)算符。 如果條件為 True,則邏輯 NOT 條件 False,否則為 True。 !(A && B) 為 True
位運(yùn)算符

&、|、^、<<、>>與主流編程語(yǔ)言沒(méi)有區(qū)別

&^:按位置零
1 &^ 0 --- 1
1 &^ 1 --- 0
0 &^ 1 --- 0
0 &^ 0 --- 0
如果右邊的操作數(shù)位上為1,不管左邊操作數(shù)為多少,結(jié)果都為0
如果右邊的操作數(shù)位上為0,那么其左邊操作數(shù)為什么,結(jié)果就是什么

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 //去掉可執(zhí)行權(quán)限
  t.Log(a&Readable == Readable, a&Writable == Writable, a&Excutable == Excutable) 
// ---> true, true, false
}
運(yùn)算符優(yōu)先級(jí)

有些運(yùn)算符擁有較高的優(yōu)先級(jí),二元運(yùn)算符的運(yùn)算方向均是從左至右。
下表列出了所有運(yùn)算符以及它們的優(yōu)先級(jí),由上至下代表優(yōu)先級(jí)由高到低:

優(yōu)先級(jí) 運(yùn)算符
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||

條件和循環(huán)

循環(huán)

GO僅支持循環(huán)關(guān)鍵字for

for i:=0; i<5; i++ {
}

///代碼示例 
package main

import "fmt"

/*while 條件循環(huán)*/
 //while(n<5)
  n := 5
  for n<5 {
      n++
      fmt.Print(n)
  }

  /*while 無(wú)限循環(huán)*/
   ///while(true)
   for true  {
        fmt.Printf("這是無(wú)限循環(huán)。\n");
    }

條件語(yǔ)句

if 語(yǔ)句:

  1. condition表達(dá)式結(jié)果必須為布爾值
  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方法支持多返回值,因此特性為編程帶來(lái)了便捷;在后面的學(xué)習(xí)章節(jié)中在詳細(xì)介紹,這里先簡(jiǎn)單拋出個(gè)例子:

package condition_test

import "testing"

func TestIfMultiSec(t *testing.T) {
     if ret, err:=function; err==nil {
        ......   
    }else{
       ......
    }
}

switch語(yǔ)句:

  1. 條件表達(dá)式不限制為常量或者表達(dá)式
  2. 單個(gè)case中,可以出現(xiàn)多個(gè)結(jié)果選項(xiàng),使用逗號(hào)分隔
  3. 與C語(yǔ)言等規(guī)則相反,Go語(yǔ)言不需要用break來(lái)明確退出一個(gè)case
  4. 可以不設(shè)定switch之后的條件表達(dá)式,在這種情況下,整個(gè)switch結(jié)構(gòu)與多個(gè)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")
         }  
     }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容