Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性...
?一、前言
當我們項目較為簡單時,我們在src目錄下新建一個該項目目錄,里面存放源碼文件即可,見下圖:
當我們一個項目較為復雜時,我們可以在src目錄下新建一個該項目目錄,在針對該項目不同模塊創建不同目錄,比如說logic(邏輯)、views(圖片渲染)、data(數據庫)等等。
二、第一個Go程序hello world
2.1 代碼
package mainimport ("fmt" )//程序執行的入口函數 func main() {fmt.Print("hello world")fmt.Printf("hello world,%d\n ", 100)fmt.Println("hello world") }2.2 相關解釋
??go語言中所有的代碼(源碼)不能夠單獨存在,必須隸屬于一個包。例:第一行package main表示hello.go屬于main包的。
? 如果是為了將代碼編譯成一個可執行程序,那么package必須是main;如果是為了將代碼編譯成庫,那么package則沒有限制。
? fmt 是go的一個系統庫,所以如果我們要使用這個系統庫就需要將fmp這個包導入,才能引用這個包中的函數和方法,而println就是fmt庫中的一個函數,fmt.println()可以打印輸出。
? go語言中,很多東西都是強制性的,需要去慢慢習慣。對于python等解釋性語言,在函數中隨便寫一些語句,就可以執行了,但go不行,go語言中,程序執行的入口就是main函數(當編譯完后,就是一個可執行程序,可雙擊執行,可執行程序的入口就是執行main函數中的內容)。?
? 注意:go語言中函數的花括號“{”一定要放在函數名所在行的行末。此處為強制性要求。
? fmt庫中,print表示打印內容,printf表示格式化輸出(%d表示占位符,指的是整型int,\n表示換行),println表示換行輸出。
2.3 編譯并執行
1、在當前終端中編譯該程序實例
?
無任何輸出是好事,表示程序無問題。
2、我們可以發現在當前目錄已經出現了一個可執行程序
?
hello.exe就是編譯后生成的可執行程序文件。
3、我們可以在當前終端目錄下直接執行該可執行程序(windows環境也可以直接去所在目錄雙擊執行即可)。
?
2.4 其他案例
上述hello world當我們在windows環境雙擊執行時,會發現打開后就退出了,這是正常的,程序執行完自然就退出了。此處我們我來寫一個等待用戶輸入之后,在退出的小例子。
注意:print是打印(輸出),而此處我們是要輸入,用到scan,因為是輸入,所以要定義一個變量來接收輸入的這個值。
package mainimport ("fmt" )//程序執行的入口函數 func main() {fmt.Print("hello world")fmt.Printf("hello world,%d\n ", 100)fmt.Println("hello world")var a intfmt.Scan(&a) //等待用戶輸入然后退出 }執行后的結果:
三、go基本命令介紹
基本命令
?? go run 快速執行go文件,就像執行腳本一樣(先編譯(編譯好文件放在一個臨時文件下)在執行。注意:需指定要編譯的源碼文件)
??? go build 編譯程序,生成二進制可執行文件(將當前目錄下所有源碼編譯)
??? go install 安裝可執行文件到bin目錄(編譯并安裝,針對當前目錄下所有源碼)
??? go test 執行單元測試或壓力測試
??? go env 顯示go相關的環境變量
???go fmt 格式化源代碼(當我們從網絡上找了些源碼格式混亂時,需要針對該源碼文件打開終端執行gofmt –w .)
一般來說我們的ide在我們保存時就已經將代碼格式化了。
補充:
1、GOPATH下全路徑編譯
當處于GOPATH路徑下進行編譯時,要寫源代碼所在全路徑時,不用寫src,因為go中已經固定死了(默認就是往src目錄下去找)。情況如下圖所示(圖中GOPATH為d:\project):
?
go intsall同go build一模一樣。
四、go的程序結構
4.1 關于注釋
單行注釋://
多行注釋:/* */
4.2 程序結構
? ?一個項目(目錄)下所有代碼文件應只屬于一個包(多個會報錯),也就是說一個目錄下寫的是一個大的功能,這些個功能只能歸屬于一個包。
?? go源碼按package進行組織,并且package要放到非注釋的第一行
?? 一個程序(代碼)只有一個main函數
?? main函數是程序的執行入口
?? 代碼是可執行程序,那么package必須是main,包是main是定死的,函數也必須是main也是定死的,否則就會報錯(因為package已經聲明了是main,那就表明這是可執行程序,如果此時函數不是main那就會報錯。)package(包) main 和func(函數)main是一一對應的。
可參考下圖更好理解main。
4.3 包的概念
1. 和python一樣,把相同功能的代碼放到一個目錄,稱之為包
2. 包可以被其他包引用
3. main包是用來生成可執行文件,每個程序只有一個main包
4. 包的主要用途是提高代碼的可復用性
五、標識符和關鍵字
1、標識符是用來表示Go中的變量名或者函數名,以字母或_開頭。后面跟著字母、 _或數字
如:_ab28 和ab_28就是合法的,88ab就是不合法的。
2、關鍵字是Go語言預先定義好的,有特殊含義的標識符。
?
?
六、變量和常量
6.1 變量
語法:var identifier type
var 變量名 變量類型
變量名 = 值
注意:
1、go語言中定義的變量必須被用到,否則會報錯(但是也有解決辦法:如果定義的變量d未被用到,我們可以使用 _ = d 來忽略變量d)
2、同時定義變量和賦值可以一步完成。
3、type可以省略不寫,系統會自動根據后面給定的值進行判別
4、Go語言中變量命名推薦駝峰語法
例1:
var a int var b string var c bool var d int = 8 var e string = "hello"?
我們會發現當定義多個變量會顯得很繁瑣,每一個都必須寫var,其實可以不用每個都寫,具體見例2.
例2:
var (a int //0 不賦值默認為0b string //“” 不賦值默認為空c bool //false 不賦值默認為falsed int = 8 // 8e string = "hello" //hello )例3打印變量小案例:
將上述定義的變量打印出來
package mainimport ("fmt" )var (a int //0 不賦值默認為0b string //“” 不賦值默認為空c bool //false 不賦值默認為falsed int = 8 // 8e string = "hello" //hello )func main() {fmt.Println(a)fmt.Println(b)fmt.Println(c)fmt.Println(d)fmt.Println(e) }?執行結果:
補充:
var a int =10 可以簡寫為 a :=10(:=表示聲明并初始化變量)
?6.2 常量
常量使用const 修飾,代表永遠是只讀的,不能修改。
語法:
const identifier [type] = value,其中type可以省略。
實例6-1???????? 例1:常規寫法
const b string = "hello world" const b = "hello world" const Pi = 3.1414926 const a = 9/3?實例6-2???????? 例2:優雅寫法
const(a = 1b = 2c = 3 )?實例6-3???????? 例3:專業寫法1
如果我們上述定義的的常量a、b、c是有序的,我們可以使用下面的專業寫法
const (a = iotab = iotac = iota ) # iota表示自動從0開始,第一行為0(以行為單位,和行數綁定,第一行為0,第二行為1,第三行為2),往后遞增。a=0,b=1,c=2 簡寫為如下:一般用簡寫 const (a = iotabc )?注意:iota是與行數相綁定的,與行號相關,下面這個例子來加深印象
package mainimport ("fmt" )const (a = 5b = iotacd = 3efg = iota )func main() {fmt.Printf("a=%d b=%d c=%d d=%d e=%d f=%d g=%d", a, b, c, d, e, f, g) }執行結果:
解釋:
第一行a=5
第二行b=iota,因為是第二行了了所以b=1(第一行iota=0,第二行iota=1)
第三行c,因為第二行是b = iota,所以相鄰c = iota,所以c=2
第四行d=3
第五行e相鄰d=3,所以e=3
第六行f也是等于3
第七行g=iota,因為是第7行了所以g=6(注意第一行是以0開始而不是1)
實例6-4???????? 例4 專業寫法2
const(a = 1 << iotabc ) #iota可以方便的迭代一個值從0以步長1遞增,0,1,2,3,4,5… 結果:a=1,b=2,c=4?七、數據類型和操作符
7.1 布爾類型
a. var b bool 和 var b bool = true 和 var b = false
b. 操作符 == 和 !=
c. 取反操作符: !b
d. && 和 || 操作符
e. 格式化輸出占位符: %t
實例7-1
package mainimport ("fmt" )func main() {var b = falsevar (c = trued bool = false)_ = d //因為此程序d變量沒有用到,此處我們將d變量賦值給_,_就相當于忽略的意思if !b {fmt.Printf("b is false\n")}if !b && c {fmt.Printf("result is true\n")}/*if b || c == true {}*/if b || c {fmt.Printf("or operation\n")} }?執行結果如下:
7.2 整數和浮點數類型
a. 符號:int8(1字節)、int16(2字節)、int32(4字節)、int64(8字節)
b. 無符號:uint8、uint16、uint32、uint64
c. int和uint和操作系統平臺相關(比如說:64位系統占8字節,32位系統占4字節,所以如果跨平臺的話最好采用a和b帶數字下標的形式,這樣可擴展性比較好)
d. float32(4字節)和float64(8字節)浮點類型
e. 所有整數初始化為0,所有浮點數初始化為0.0,布爾類型初始化為false
f. Go是強類型語言,不同類型相加以及賦值是不允許的(比如說:定義為int,永遠是int類型。int和int32是不同類型,不能相加也不能互相賦值)
g. 那怎么樣才能實現,不同類型相加呢?
?比如:int和int32類型想要相加,那必須得做一個強制轉換,轉換成相同類型數據才能相加或者賦值
h. 輸出占位符:整數%d, %x十六進制, %f浮點數
?補充:
1字節===8個二進制位===11111111 相當于最大值256(2^8) 如果有符號的話最大值是127
實例7-2
package mainimport ("fmt" )func main() {var a int = 10var b int32 = 10var c intc = a + int(b)var d int = int(b)fmt.Print(a, b, c, d)fmt.Println() //不輸出任何值表示換行fmt.Printf("%x\n", c) //輸出16進制c }?執行結果:
7.3 字符串類型
a. var str string
b. var str string = “hello world”
c. 字符串輸出占位符%s
d. 萬能輸出占位符: %v (當不確定數據具體是什么類型時,用什么占位符時,系統自動幫我們進行轉換。)
package mainimport ("fmt" )func main() {var b string = "hello"var c = "hello"fmt.Printf("b=%v and c=%s\n", b, c) }?執行結果:
?
7.4 字符串的兩種表示方式
a. 雙引號, “”,可以包含控制字符
b. 反引號, ``,所有字符都是原樣輸出
c.字符必須用單引號括起來,不能用雙引號,字符串用雙引號。
實例7-3
package mainimport ("fmt" )func main() {var str = "hello world\n\n" // \n是控制字符換行,""的話可以包含控制字符,輸出換行var str2 = `hello \n \n \n` // ``所有字符都會原樣輸出fmt.Println("str=", str)fmt.Println("str2=", str2) }?輸出結果:
實例7-4
package mainimport ("fmt" )func test_str1() {var b string = "hello\n\n\n"var c = "hello"fmt.Printf("b=%v and c = %s\n", b, c) } func test_str2() {var b string = `床前明月光\n,疑是地上霜。舉頭望明月,低頭思故鄉。`fmt.Printf("b %s\n", b) } func test_char() {var c rune //rune用來表示一個utf8的字符c = 20320var d byte //byte表示一個字節d = 'd'//c = '你' //'你'的utf8編碼是20320,所以下面代碼輸出‘你’var e rune = '喊'fmt.Printf("c=%c d=%c e=%c\n", c, d, e) // %c輸出字符 } func main() {test_str1()test_str2()test_char() }?輸出結果:
補充:go語言中支持以下格式輸出。
目前printf支持以下格式的輸出,例如:
printf("%c",a);輸出單個字符。
printf("%d",a);輸出十進制整數。
printf("%f",a);輸出十進制浮點數.
printf("%o",a);輸出八進制數。
printf("%s",a);輸出字符串。
printf("%u",a);輸出無符號十進制數。
printf("%x",a);輸出十六進制數。
7.5 操作符
a. 邏輯操作符, == 、 != 、 <、 <=、 >=
b. 算數操作符, +、 -、 *、 /、 %
八、 Go程序的基本結構延伸
1. 任何一個代碼文件隸屬于一個包
2. import 關鍵字,引用其他包:
import "fmt"
import("os")
通常習慣寫成:
import (
"fmt"
"os"
)
3. 開發可執行程序, package main,
并且有且只有一個main入口函數。
4. 包中函數調用:
a. 同一個包中函數,直接用函數名調用
b. 不同包中函數,通過包名+點+函數名進行調用
5. 包訪問控制規則:
a. 大寫意味著這個函數/變量是可導出
b. 小寫意味著這個函數/變量是私有的,包外部不能訪問
實例8-1
目錄結構:
calc:做第三方庫
calc.go
package calcimport ("fmt" )func Add(a int, b int) int {var c = a + bfmt.Printf("add result:%d\n", c)return c }?編譯安裝為靜態庫:
編譯后的靜態庫:(main包為可執行包,編譯后的文件為.go后綴二進制文件,main之外的包,編譯后存在pkg下,后綴為.a文件)
可執行程序main.go
package mainimport ("day1/calc""fmt" )func main() {var c intc = calc.Add(2, 3)fmt.Printf("c=%d\n", c) }?執行結果:
九、 Go語言特性
1. 垃圾回收
a. 內存自動回收,再也不需要開發人員管理內存
b. 開發人員專注業務實現,降低了心智負擔
c. 只需要new分配內存,不需要釋放
?
2. 天然并發
a. 從語言層面支持并發,非常簡單(用戶態實現,避免了用戶態和內核態的頻繁切換)
b. goroutine(協程),輕量級線程,創建成千上萬個goroute成為可能(go成千上萬個goroutine在用戶態跑時,可能操作系統(內核)只有幾千個線程再跑,java有多少個線程在用戶態跑,就有多少個線程在內核態跑)
c. 基于CSP(Communicating Sequential Process)模型實現(其實就是goroutine+channel,線程之間通信借助管道)
實例9-1???????? ?
原有程序案例是:
calc.go
package calcimport ("fmt" )func Add(a int, b int) int {var c = a + bfmt.Printf("add result:%d\n", c)return c }main.go 示例1
package mainimport ("day1/calc""fmt" )func main() {var c intcalc.Add(2, 3)fmt.Printf("c=%d\n", c) }目前是同步執行的,如果想要異步執行,只需要如下(標紅)操作即可,那樣就變成多線程的了,代碼示例如下:
main.go
示例2:
package mainimport ("day1/calc""fmt" )func main() {var c intgo calc.Add(2, 3)fmt.Printf("c=%d\n", c) }?接下來演示效果:
如果是單線程跑,代碼示例如示例1:執行結果如下:
解釋:單線程跑的話,是同步的,先調函數打印出加法計算結果,然后在打出c的值。單線程是順序輸出,固定輸出的。
如果是多線程跑,代碼示例如示例2:實行結果如下:
解釋:
go calc.Add(2, 3) 相當于起了一個線程再跑,fmt.Printf("c=%d\n", c),是另一個線程(主線程)再跑,為什么最后只打印出一個c=0,是因為主線程執行完了,退出了,其他的線程就沒有機會執行了。多線程是哪一個線程調度的快,哪一個線程就優先輸出,主線程優先輸出的話,其他線程就沒有機會執行了。
?
3. channel
a. 管道,類似unix/linux中的pipe(隊列)
b. 多個goroute之間通過channel進行通信
c. 支持任何類型
實例9-2
package mainimport ("fmt" )func main() {p := make(chan int, 3)p <- 1p <- 2var b intb = <-pfmt.Printf("b = %d\n", b) }輸出結果:
解釋:
make(chan int,3):chan就是管道類型關鍵字,int表示管道中放什么類型數據,3表示管道空間,也就是管道的容量
p <- 1:就表示往管道中放數據
b = <- p:表示從管道中把數據取出來給變量b
輸出的b的結果為1:,是因為隊列先進先出。
?
注意:
管道容量為3,當放入的數據多于3個時,就會報死鎖的錯誤。
代碼如下:
執行結果:
死鎖是最近新版本加入,舊的版本會直接卡在哪里等待。
?
4. 多返回值
a. 一個函數返回多個值
實例9-3 ? ? ? ??
定義多個返回值,就要返回多個,不然會報錯,都是一一對應的。
實例9-4
package mainimport ("fmt" )func Calc(a int, b int) (int, int) {return a + b, a - b }func main() {a1, b1 := Calc(2, 5)fmt.Printf("a1=%d b1=%d\n", a1, b1) }?執行結果:
?
?
轉載于:https://www.cnblogs.com/forever521Lee/p/9263402.html
總結
以上是生活随笔為你收集整理的Go语言基础之1--标识符、关键字、变量和常量、数据类型、Go的基本程序结构、Golang的特性...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到游泳了是什么意思
- 下一篇: 梦到全是血是什么意思