環境部署
Go
編譯器
安裝位置:
C:\Program Files\Go
其他配置
-
創建一個任意的目錄
GolangProjects
,目錄結構如下GolangProjects --bin --- crm.exe //主程序入口文件 --pkg --- commlib.A //包文件 --src
配置環境變量
- 添加環境變量
GOROOT
:C:\Program Files\Go
Go 編譯器的安裝目錄 - 添加環境變量
GOBIN
:E:\Code\GoLangProjects\bin
方便直接 Go - 添加環境變量
GOPATH
:E:\Code\GoLangProjects
vs code
配置環境
tools 怎麼來的
-
github中文:https://github.com/Go-zh/tools.git
-
github英文:https://github.com/golang/tools.git
上述倆 GitHub 地址沒有通天的手段基本上是整不下來的,這個時候
碼雲
可以出來了把上述的那倆git地址都挪到碼雲裏,這個方便本地clone
Clone 無需多言
推薦使用:SourceTree ,主要界面看着挺爽
怎麼擺放
在本地go_path
目錄下新建文件夾,如下結構
-- go path
--- bin
--- pkg
--- src
---- github.com
------ Go-zh
------- tools //https://github.com/Go-zh/tools.git
---- golang.org
----- x
------ mod //https://github.com/golang/mod.git
------ sys //https://github.com/golang/sys.git
------ tools //https://github.com/golang/tools.git
------ xerrors //https://github.com/golang/xerrors.git
安裝命令
打開 go-path 目錄的下的src 目錄,地址欄裏輸入 cmd ,啓動終端,輸入如下命令:
1. go install golang.org/x/tools/cmd/guru
2. go install golang.org/x/tools/cmd/gorename
3. go install golang.org/x/tools/cmd/fiximports
4. go install golang.org/x/tools/cmd/gopls
5. go install golang.org/x/tools/cmd/godex
注意:
我個人在第4點出錯了,原因是因爲英文官方的tools中按照位置找過去沒有gopls;
百度過後才下載的中文社區的,由此纔看到前面的目錄結構。
所以到這要安裝gopls
,執行如下命令:
go install github.com/Go-zh/tools/cmd/gopls
vscode
運行代碼
-
一般姿勢:
啓動vscode終端,cd 到
go-path
目錄下的src
,再找到指定指定go
文件,例如:go run app.go
-
進階姿勢:
啓動vscode擴展,安裝 code run 插件,安裝按完重啓編輯器,只需要右鍵選擇code run 即可,或者快捷鍵
ctrl + alt + n
運行代碼
src
目錄下添加go文件
-src
--crm
---app.go
-- app.go
package main
import "fmt"
func main() {
fmt.Printf("Hello Go~ 叫爸爸~")
}
--commlib
---page
package commlib
func Add(i int ,j int)int {
return i+j
}
運行有三種方式:
進入項目目錄執行:
go run app.go
go build app.go
執行完此命令後,會在同級目錄下面添加同名exeapp.exe
可執行程序,然後cmd
中執行exe
程序即可。與第一種方式相同,只是go run
相當於一起把此方式中的兩步驟一次執行完畢。go install
執行完命令後,會在外面那個Bin
文件夾生產一個exe
可執行文件,crm.exe
,也可以在cmd
命令中執行,於上面第二種方式的區別在於,會在Bin
文件夾中生成exe
可執行文件。但是如果生成的項目不是主程序入口、只有方法的話,就會生成包文件commlib.A
文件,類似於C# 中類,存放在bin文件夾的同級目錄pkg
文件夾中。
Go
包管理
初識包管理
- 一個文件夾也可以稱之爲一個包
- 在文件夾(包)中可以創建多個文件
- 在同一個包下的每個文件中必須指定
包名稱且相同
包的分類
main
包,如果是main
包,必須寫一個main
函數,以此作爲程序的入口,又稱爲主函數,編譯生成後會生成一個可執行文件。- 非
main
包
調用包
調用包文件內的方法:
package main
import (
"commlib" //這裏會引入包
"fmt"
"strconv" //引入包
)
func main() {
//println 自帶輸出換行
fmt.Println("Hello Go~ ")
//調用
var num int = commlib.Add(1,6)
//strconv.itba()方法,int 轉 string
fmt.Println(strconv.Itoa(num))
}
package commlib
func Add(i int ,j int)int {
return i+j
}
包定義規範
- 定義包文件之後,包內的函數首字母必須得大寫
- 大寫和小寫的區別:
- 大寫:類似於C# 中的 public 修飾符,包的外部可以進行調用
- 小寫:類似於C# 中的 internal修飾符,僅限於包內部使用
截圖
2021.05.05
基礎知識
輸出
在終端輸出前置語言例如:請輸入賬戶名或者密碼等等...
- 內置函數
print
- 默認打印兩個
print
是連在一起的,如果想要達到換行效果需要在內容尾部加上\n
- 默認打印兩個
println
- 默認打印兩個
println
是自帶換行效果的
- 默認打印兩個
fmt
fmt.print
- 效果通內置函數 print 相仿
fmt.println
- 同上,平時推薦使用此方法
fmt.println
擴展:fmt.println("我叫","Harris","年齡","18")
中間自帶空格- 格式化顯示:
fmt.printF()
- 在以上兩種方式的輸出中推薦使用
fmt
,原因:Golang
官方給出的回答是,在以後的規劃中,不保證內置函數可以繼續使用,爲防止後面禁用內置函數後,代碼出問題。
註釋
- 單行註釋 //
- 多行註釋 /* */
GoLand
快捷鍵Ctrl+?
變量
-
概述
- Go 是靜態類型語⾔,不能在運⾏期改變變量類型
- 使⽤關鍵字 var 定義變量,⾃動初始化爲零值。如果提供初始化值,可省略變量類型,由 編譯器⾃動推斷。
- 聲明的變量必須使用 如果聲明不使用,則報錯 編譯器會將未使⽤的局部變量當做錯誤
-
變量的作用域
-
全局變量:沒有寫在函數內的變量,稱之爲全局變量,個人理解。
var name string = "Harris" var name = "Harris" var { v1 = "a" v2 = "b" v3 = 18 v4 int } name := "Harris" //這種不行滴
-
局部變量:函數內的變量 局部就和C#差不多了
func main(){ var name string = "Harris" name := "Harris" var name = "Harris" var{ name = "Harris" age = 18 } }
-
多變量賦值時,先計算所有相關值,然後再從左到右依次賦值
data, i := [3]int{0, 1, 2}, 0 i, data[i] = 2, 100 // (i = 0) -> (i = 2), (data[0] = 100) fmt.Println(i,data) //結果:2 [100 1 2]
-
特殊只寫變量 "_",⽤於忽略值佔位
func test() (int, string) { return 1, "abc" } func main() { _, s := test() fmt.Println(s) //結果:abc }
-
編譯器會將未使⽤的局部變量當做錯誤
func main() { i := 0 // Error: i declared and not used。(可使⽤ "_ = i" 規避) }
-
常量
-
常量值必須是編譯期間固定的數字、字符串、布爾值
const x,y int = 1,2 //多常量初始化 const z = "Hello World" //類型推斷 const{ a,b = 1,2 c bool = true } func main(){ const x = "xxxx" //這個時候如果沒有使用上述已經定義好的常量,不會報錯 }
-
常量可以使用在編譯期間確定的函數
const a,b int =1,2 const c = "abc" const x = len(c) const y = unsafe.Sizeof(x) //這個方法是用來計算字節的,64爲系統中,字符串和整形的字節一個都是8 fmt.Println(a) fmt.Println(b) fmt.Println(c) fmt.Println(x) fmt.Println(y) //結果: /* 1 2 abc 3 8*/
枚舉
-
關鍵字 iota 定義常量組中從 0 開始按⾏計數的⾃增枚舉值。
const( Sunday = iota //0 Monday //1,通常省略後面的表達式 Tuesday //2 Wednesday //3 Thursday //4 Friday //5 Saturday //6 ) const ( _ = iota // iota = 0 KB int64 = 1 << (10 * iota) // iota = 1 << 是左移運算符 MB // 與 KB 表達式相同,但 iota = 2 GB TB ) fmt.Println(KB,MB,GB) //1024 1048576 1073741824
-
在同⼀常量組中,可以提供多個 iota,它們各⾃增⻓。
const ( A, B = iota, iota << 10 // 0, 0 << 10 C, D // 1, 1 << 10 ) fmt.Println(A,B,C,D) //0 0 1 1024
-
如果 iota ⾃增被打斷,須顯式恢復
const ( A = iota // 0 B // 1 C = "c" // c D // c,與上⼀⾏相同。 E = iota // 4,顯式恢復。注意計數包含了 C、D 兩⾏。 F // 5 ) fmt.Println(A,B,C,D,E,F)//0 1 c c 4 5
-
可通過⾃定義類型來實現枚舉類型限制
type Color int const ( Black Color = iota Red Blue ) func test(c Color)Color { return c } func main() { c := Black fmt.Println(test(c)) // 0 x := 1 test(x) // Error: cannot use x (type int) as type Color in function argument;寫的時候就會報錯沒法轉換 }
數據類型
- 空指針值 nil,⽽⾮ C/C++ NULL。
引用類型
切片(Slice)
實現類似動態數組的功能
package commlib
import "fmt"
func SliceTest1() {
x:=make([]int,0,5)//聲明一個容量爲5的切片
for i:=0;i<8;i++ {
x= append(x,i) //向切片內追加數據,當超出容量後,自動分配更大的容量空間
}
fmt.Println(x)
}
輸出結果:
channel 通道
表達式
常用
package commlib
import "fmt"
//ExpressionTest
func ExpressionTest() {
//if
fmt.Println("******IF******")
x:=100
y:=6
if x > 0{
fmt.Println("x+")
}else if x < 0{
fmt.Println("x-")
}else {
fmt.Println("0")
}
// swich
fmt.Println("******swich******")
switch {
case x > 0:
fmt.Println("100")
case x<0:
fmt.Println("250")
default:
fmt.Println("倆250")
}
// for
fmt.Println("******for++******")
for i:=0;i<5;i++ {
fmt.Println(i)
}
fmt.Println("******for--******")
for i:=5;i>1;i--{
fmt.Println(i)
}
fmt.Println("******相當於while(x<10)******")
for y<10{
y++
fmt.Println(y)
}
fmt.Println("******相當於while(true)******")
for{
fmt.Println(x)
x = x-50
if x == 0 {
break
}
}
fmt.Println("******返回索引和值******")
arr:=[]int{1,2,3,4,5}
for i,n := range arr{
fmt.Println(i,":",n)
}
}
執行結果:
標籤
for
標籤
fmt.Println("給For 打標籤,應用 break | continue 跳出或者終止循環")
f1:for i:=0;i<4;i++{ //f1 標籤
for j:=0;j<4;j++{
if i==2{
break f1 //此處結束的循環是f1 標籤所對應的i for 循環
}
fmt.Println(i,j)
}
}
輸出結果:
goto
跳躍
- 跳躍到指定行,然後向下執行代碼
package api
import "fmt"
func GotoMethod() {
fmt.Println("請輸入姓名:")
var name string
fmt.Scanln(&name)
if name == "Harris"{
goto SVIP
}else if name=="Dongjie"{
goto VIP
}
fmt.Println("預約...")
VIP:
fmt.Println("等號...")
SVIP:
fmt.Println("治療...")
}
字符串格式化
package api
import "fmt"
func StringFormatMenthod() {
var name,address,action string
fmt.Println("請輸入姓名")
fmt.Scanln(&name)
fmt.Println("請輸入地址")
fmt.Scanln(&address)
fmt.Println("請輸入行爲")
fmt.Scanln(&action)
result := fmt.Sprintf("我叫%s,我正在%s旁邊%s",name,address,action)
fmt.Println(result)
}
輸出:
運算符
位運算符
進制轉換:
例如:101000 -> 2*5 + 2**3 -> 32 + 8 = 40
1. 按位進行與運算(全爲1,才得1)
r1 := 5 & 99
5 -> 0000101
99 -> 1100011
0000001 -> 1
2. 按位進行或運算(只要有1,就得1)
r2 := 5 | 99
5 -> 0000101
99 -> 1100011
1100111 -> 2*6 +2*5 +2*2 + 2*1 + 2*0 -> 64+32+4+2+1 = 103
3. 按位進行異或運算(上下不同,就得1)
r3 := 5 ^ 99
5 -> 0000101
99 -> 1100011
1100110 -> 2*6 +2*5 +2*2 + 2*1 -> 64+32+4+2 = 102
4. 按鈕進行左移運算
r4 := 5 << 2
5 -> 0000101 -> 101 //前面的0可以省略
所以:101 左移之後 後面補0 -> 10100 -> 2*4+2*2 -> 16+4 = 20
5. 按位進行右移運算
r5 := 5 >> 1
5 -> 0000101 -> 101 //前面的0可以省略
所以:101 右移之後 10 右移1位,後面咬去1位, -> 10 -> 2*1 = 2
補充:
-
十進制轉二進制
十進制 二進制(逢二進一) 0 0 1 1 2 10 3 11 4 100 5 101 6 110 7 111 8 1000 9 1001 10 1010
函數
package commlib
import (
"errors"
"fmt"
)
// 函數可以定義多個返回值,甚至對其命名
func FunctionTest(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("FunctionTest")
}
return a / b, nil
}
func FunctionTest2() {
a, b := 1, 0 //定義多個變量
c, err := FunctionTest(a, b) //接受多個返回值
fmt.Println(c, err)
}
//函數是第一類型,可以作爲參數或者返回值
func FunctionTest3(x int)func() {//返回函數類型
return func() {//匿名函數
fmt.Println("返回參數爲函數",x)//閉包
}
}
func FunctionTest4() {
x:=100
f:=FunctionTest3(x)//返回函數
f()//執行函數
}
//通過關鍵字 defer 來修飾動作標識最後執行
func FunctionTest5(a,b int) {
defer fmt.Println("延遲執行的動作")
fmt.Println("正在執行的動作")
fmt.Println(a+b)
}
func FunctionTest6() {
x,y := 10,0
FunctionTest5(x,y)
}
執行:
fmt.Println("執行:FunctionTest2")//函數可以定義多個返回值,甚至對其命名
commlib.FunctionTest2()
fmt.Println("執行:FunctionTest4")//函數是第一類型,可以作爲參數或者返回值
commlib.FunctionTest4()
fmt.Println("執行:FunctionTest6")//通過關鍵字 defer 來修飾動作標識最後執行
commlib.FunctionTest6()
執行結果:
常見問題
-
go.mod file not found in current directory or any parent directory; see 'go help modules'
問題是go環境的問題:執行
go env -w GO111MODULE=auto
-
修改配置:運行種類和包位置 可以解決運行只侷限在某個文件的問題