Go學習(2):基本語法
基本語法
一、二進位制、八進位制、十進位制、十六進位制【擴充套件內容】
1.1 進位制
二進位制:逢二進一,數值只有0和1。
八進位制:逢八進一,數值有0,1,2,3,4,5,6,7
十進位制:逢十進一,數值有0,1,2,3,4,5,6,7,8,9
十六進位制:逢十六進一,數值有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
1.2 進位制轉換
二進位制、八進位制、十六進位制轉為十進位制
十進位制轉為二進位制、八進位制、十六進位制
1.3 原碼,反碼,補碼
1.3.1 機器數和真值
機器數:一個數在計算機中的二進位制表示形式。叫做這個數的機器數。機器數是帶符號的,最高位0表示正數,1表示負數。 示例: 比如10進制中的+3,計算機長度為8位。轉為二進位制是0000 0011。 比如-3,轉為二進位制是1000 0011。 真值:就是我們日常說的十進位制的正數,負數和0,比如-1,-2,-100,0,1,2,1000,100000等等。 因為第一位是符號位,所以機器數的形式值就不等於真正的數值。 比如1000 0011, 作為負數可以是-3,作為正數可以說131. 為了區分,將帶符號位的計算數對應的真正的數值稱為機器數的真值。
1.3.2 原碼,反碼,補碼
原碼:就是符號位加上真值的絕對值,即第一位表示符號位,其餘位表示值。 +1 = [0000 0001]原 -1 = [1000 0001]原 原碼是人腦最容易理解和計算的表示方式. 反碼:正數的反碼是其本身,負數的反碼是在其原碼的基礎上,符號位不變,其餘各位按位取反。 +1 = [0000 0001]原 = [0000 0001]反 -1 = [1000 0001]原 = [1111 1110]反 一個反碼錶示的是負數, 人腦無法直觀的看出來它的數值. 通常要將其轉換成原碼再計算。 補碼:正數的補碼是其本身,負數的補碼是在原碼的基礎上,符號位不變,其餘各位取反後+1。 +1 = [0000 0001]原 = [0000 0001]反 = [0000 0001]補 -1 = [1000 0001]原 = [1111 1110]反 = [1111 1111]補 對於負數, 補碼錶示方式也是人腦無法直觀看出其數值的. 通常也需要轉換成原碼在計算其數值.
於是人們開始探索 將符號位參與運算, 並且只保留加法的方法. 首先來看原碼。計算十進位制的表示式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
如果用原碼錶示, 讓符號位也參與計算, 顯然對於減法來說, 結果是不正確的.這也就是為何計算機內部不使用原碼錶示一個數.
為了解決原碼做減法的問題, 出現了反碼。計算十進位制的表示式:
1-1=0
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0發現用反碼計算減法, 結果的真值部分是正確的. 而唯一的問題其實就出現在”0”這個特殊的數值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.
於是補碼的出現, 解決了0的符號以及兩個編碼的問題:
1-1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]補 + [1111 1111]補
= [0000 0000]補=[0000 0000]原這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128:
二、變數與常量
2.1 什麼是變數
變數是為儲存特定型別的值而提供給記憶體位置的名稱。在go中宣告變數有多種語法。
2.2 宣告變數
var名稱型別是宣告單個變數的語法。
以字母或下劃線開頭,由一個或多個字母、數字、下劃線組成
宣告一個變數
第一種,指定變數型別,聲明後若不賦值,使用預設值
var name type
name = value
第二種,根據值自行判定變數型別(型別推斷Type inference)
如果一個變數有一個初始值,Go將自動能夠使用初始值來推斷該變數的型別。因此,如果變數具有初始值,則可以省略變數宣告中的型別。
var name = value
第三種,省略var, 注意 :=左側的變數不應該是已經宣告過的(多個變數同時宣告時,至少保證一個是新變數),否則會導致編譯錯誤(簡短宣告)
name := value
// 例如
var a int = 10
var b = 10
c : = 10
這種方式它只能被用在函式體內,而不可以用於全域性變數的宣告與賦值
示例程式碼:
package main
var a = "Hello"
var b string = "World"
var c bool
func main(){
println(a, b, c)
}
執行結果:
Hello World false
多變數宣告
第一種,以逗號分隔,宣告與賦值分開,若不賦值,存在預設值
var name1, name2, name3 type
name1, name2, name3 = v1, v2, v3
第二種,直接賦值,下面的變數型別可以是不同的型別
var name1, name2, name3 = v1, v2, v3
第三種,集合型別
var (
name1 type1
name2 type2
)
注意事項
如果在相同的程式碼塊中,我們不可以再次對於相同名稱的變數使用初始化宣告,例如:a := 20 就是不被允許的,編譯器會提示錯誤 no new variables on left side of :=,但是 a = 20 是可以的,因為這是給相同的變數賦予一個新的值。
如果你在定義變數 a 之前使用它,則會得到編譯錯誤 undefined: a。
如果你聲明瞭一個區域性變數卻沒有在相同的程式碼塊中使用它,同樣會得到編譯錯誤,例如下面這個例子當中的變數 a:
func main() {
var a string = "abc"
fmt.Println("hello, world")
}
嘗試編譯這段程式碼將得到錯誤 a declared and not used
此外,單純地給 a 賦值也是不夠的,這個值必須被使用,所以使用
在同一個作用域中,已存在同名的變數,則之後的宣告初始化,則退化為賦值操作。但這個前提是,最少要有一個新的變數被定義,且在同一作用域,例如,下面的y就是新定義的變數
package main
import (
"fmt"
)
func main() {
x := 140
fmt.Println(&x)
x, y := 200, "abc"
fmt.Println(&x, x)
fmt.Print(y)
}
執行結果:
0xc04200a2b0
0xc04200a2b0 200
abc
空白識別符號 _ 也被用於拋棄值,如值 5 在:_, b = 5, 7 中被拋棄
_ 實際上是一個只寫變數,你不能得到它的值。這樣做是因為 Go 語言中你必須使用所有被宣告的變數,但有時你並不需要使用從一個函式得到的所有返回值
並行賦值也被用於當一個函式返回多個返回值時,比如這裡的 val 和錯誤 err 是通過呼叫 Func1 函式同時得到:val, err = Func1(var1)
1.變數必須先宣告,才能夠使用,而且每個變數只能被宣告一次。
2.因為go是強型別語言,賦值型別要對應
3.name := value,這種宣告變數的方式,不能在函式外部使用
4.預設值:也叫零值。
2.3 常量宣告
常量是一個簡單值的識別符號,在程式執行時,不會被修改的量。
常量中的資料型別只可以是布林型、數字型(整數型、浮點型和複數)和字串型
不曾使用的常量,在編譯的時候,是不會報錯的
顯示指定型別的時候,必須確保常量左右值型別一致,需要時可做顯示型別轉換。這與變數就不一樣了,變數是可以是不同的型別值
const identifier [type] = value
顯式型別定義: const b string = "abc"
隱式型別定義: const b = "abc"
package main
import "fmt"
func main() {
const LENGTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" //多重賦值
area = LENGTH * WIDTH
fmt.Printf("面積為 : %d", area)
println()
println(a, b, c)
}
執行結果:
面積為 : 50
1 false str
常量可以作為列舉,常量組
const (
Unknown = 0
Female = 1
Male = 2
)
常量組中如不指定型別和初始化值,則與上一行非空常量右值相同
package main
import (
"fmt"
)
func main() {
const (
x uint16 = 16
y
s = "abc"
z
)
fmt.Printf("%T,%v\n", y, y)
fmt.Printf("%T,%v\n", z, z)
}
執行結果:
uint16,16
string,abc
2.4 iota
iota,特殊常量,可以認為是一個可以被編譯器修改的常量
在每一個const關鍵字出現時,被重置為0,然後再下一個const出現之前,每出現一次iota,其所代表的數字會自動增加1
iota 可以被用作列舉值:
const (
a = iota
b = iota
c = iota
)
第一個 iota 等於 0,每當 iota 在新的一行被使用時,它的值都會自動加 1;所以 a=0, b=1, c=2 可以簡寫為如下形式:
const (
a = iota
b
c
)
iota 用法
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //獨立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢復計數
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
執行結果:
0 1 2 ha ha 100 100 7 8
如果中斷iota自增,則必須顯式恢復。且後續自增值按行序遞增
自增預設是int型別,可以自行進行顯示指定型別
數字常量不會分配儲存空間,無須像變數那樣通過記憶體定址來取值,因此無法獲取地址
三、基本資料型別
以下是go中可用的基本資料型別
2.1 布林型bool
布林型的值只可以是常量 true 或者 false。一個簡單的例子:var b bool = true
2.2 數值型
1、整型
- int8
有符號 8 位整型 (-128 到 127) - int16
有符號 16 位整型 (-32768 到 32767) - int32
有符號 32 位整型 (-2147483648 到 2147483647) - int64
有符號 64 位整型 (-9223372036854775808 到 9223372036854775807) - uint8
無符號 8 位整型 (0 到 255) - uint16
無符號 16 位整型 (0 到 65535) - uint32
無符號 32 位整型 (0 到 4294967295) - uint64
無符號 64 位整型 (0 到 18446744073709551615)
int和uint:根據底層平臺,表示32或64位整數。除非需要使用特定大小的整數,否則通常應該使用int來表示整數。
大小:32位系統32位,64位系統64位。
範圍:-2147483648到2147483647的32位系統和-9223372036854775808到9223372036854775807的64位系統。
2、浮點型
-
float32
IEEE-754 32位浮點型數
-
float64
IEEE-754 64位浮點型數
-
complex64
32 位實數和虛數
-
complex128
64 位實數和虛數
3、其他
-
byte
類似 uint8
-
rune
類似 int32
-
uint
32 或 64 位
-
int
與 uint 一樣大小
-
uintptr
無符號整型,用於存放一個指標
2.3 字串型
字串就是一串固定長度的字元連線起來的字元序列。Go的字串是由單個位元組連線起來的。Go語言的字串的位元組使用UTF-8編碼標識Unicode文字
var str string
str = "Hello World"
2.4 派生型別(複合型別)
(a) 指標型別(Pointer)
(b) 陣列型別
(c ) 結構化型別(struct)
(d) Channel 型別
(e) 函式型別
(f) 切片型別
(g) 介面型別(interface)
(h) Map 型別
四、運算子
3.1 算術運算子
+ - * / %(求餘) ++ --
3.2 關係運算符
== != > < >= <=
3.3 邏輯運算子
運算子 | 描述 |
---|---|
&& | 所謂邏輯與運算子。如果兩個運算元都非零,則條件變為真 |
|| | 所謂的邏輯或操作。如果任何兩個運算元是非零,則條件變為真 |
! | 所謂邏輯非運算子。使用反轉運算元的邏輯狀態。如果條件為真,那麼邏輯非操後結果為假 |
3.4 位運算子
A | B | A&B | A|B | A^B |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
這裡最難理解的就是^了,只要認為AB兩者都相同的時候,為0,其他都為1
假設A為60,B為13
運算 | 描述 | 示例 |
---|---|---|
& | 二進位制與操作副本位的結果,如果它存在於兩個運算元 | (A & B) = 12, 也就是 0000 1100 |
| | 二進位制或操作副本,如果它存在一個運算元 | (A | B) = 61, 也就是 0011 1101 |
^ | 二進位制異或操作副本,如果它被設定在一個運算元但不能同時是位元 | (A ^ B) = 49, 也就是 0011 0001 |
<< | 二進位制左移位運算子。左邊的運算元的值向左移動由右運算元指定的位數 | A << 2 will give 240 也就是 1111 0000 |
>> | 二進位制向右移位運算子。左邊的運算元的值由右運算元指定的位數向右移動 | A >> 2 = 15 也就是 0000 1111 |
3.5 賦值運算子
運算子 | 描述 | 示例 |
---|---|---|
= | 簡單的賦值操作符,分配值從右邊的運算元左側的運算元 | C = A + B 將分配A + B的值到C |
+= | 相加並賦值運算子,它增加了右運算元左運算元和分配結果左運算元 | C += A 相當於 C = C + A |
-= | 減和賦值運算子,它減去右運算元從左側的運算元和分配結果左運算元 | C -= A 相當於 C = C - A |
*= | 乘法和賦值運算子,它乘以右邊的運算元與左運算元和分配結果左運算元 | C *= A is equivalent to C = C * A |
/= | 除法賦值運算子,它把左運算元與右運算元和分配結果左運算元 | C /= A 相當於 C = C / A |
%= | 模量和賦值運算子,它需要使用兩個運算元的模量和分配結果左運算元 | C %= A 相當於 C = C % A |
<<= | 左移位並賦值運算子 | C <<= 2 相同於 C = C << 2 |
>>= | 向右移位並賦值運算子 | C >>= 2 相同於 C = C >> 2 |
&= | 按位與賦值運算子 | C &= 2 相同於 C = C & 2 |
^= | 按位異或並賦值運算子 | C ^= 2 相同於 C = C ^ 2 |
|= | 按位或並賦值運算子 | C |= 2 相同於 C = C | 2 |
3.6優先順序
運算子優先順序
有些運算子擁有較高的優先順序,二元運算子的運算方向均是從左至右。下表列出了所有運算子以及它們的優先順序,由上至下代表優先順序由高到低:
優先順序 | 運算子 |
---|---|
7 | ^ ! |
6 | * / % << >> & &^ |
5 | + - | ^ |
4 | == != < <= >= > |
3 | <- |
2` | && |
1 | || |
當然,你可以通過使用括號來臨時提升某個表示式的整體運算優先順序。