Golang基礎學習總結
1、不支持繼承 重載 ,比如C++Java的接口,接口的修改會影響整個實現改接口的類行為的修改,Go 設計者認為這一特點或許根本沒用.
2、必任何函數定義必須花括號跟在函數聲明后面而不能換行 如 func funca(a int){},在Go語言中 函數也是一種類型 可以被推導 使用支持匿名函數 和閉包。
函數的返回值支持多重返回類似Python , 如果不賦值 整數類型默認 0 浮點數類型默認0.0 error類型 默認是nil
3、不用的包一定不要引入,這是Go的原則,就如Python的嚴格制表符對其一樣 ,和 unused 變量都會被 編譯器所報錯
4、package做為引入包用。
5、import "a" 調用包內部的函數 a.xx()
6、CGo是Go語言的一個特性,可以方便快速的在Go中調用C 相比Java JNI簡單容易實現
7、go通過goroutine 進行協程優化 提高并發性能。 動態線程調整。
8、6g和6l是64位版本的Go編譯器和鏈接器,對應的32位版本工具為8g和8l。Go還有另外一個 GCC版本的編譯器,名為 gccgo。
9、注意多個go文件可以用同一個包名字,如果要為 Go生成可執行文件 那么必須 進行 package main
main函數的聲明
func main()
{
args := os.Args
if args == nil || len(args) < 2 {
return
}
10、Linux 為了能夠構建這個工程, 需要先把這個工程的根目錄加入到環境變量GOPATH中。 假設calcproj 目錄位于~/goyard下,則應編輯~/.bashrc文件,并添加下面這行代碼:
export GOPATH=~/goyard/calcproj
然后執行以下命令應用該設置: $ source ~/.bashrc ,GOPATH和PATH環境變量一樣,也可以接受多個路徑,并且路徑和路徑之間用冒號分割。
設置完GOPATH后,現在我們開始構建工程。假設我們希望把生成的可執行文件放到 calcproj/bin目錄.
11、GoRoot go安裝路徑 ....上面的時候工程路徑
12、GDB調試
不用設置什么編譯選項, Go語言編譯的二進制程序直接支持GDB調試, 比如之前用go build calc編譯出來的可執行文件calc,就可以直接用以下命令以調試模式運行:
$ gdb calc
因為GDB的標準用法與Go沒有特別關聯,這里就不詳細展開了,有興趣的讀者可以自行查
看對應的文檔。需要注意的是,Go編譯器生成的調試信息格式為DWARFv3,只要版本高于7.1
的GDB應該都支持它。
13、Go語言會被稱為“更好的C語言”
14、每一行不需要加分號自動添加
15 、添加了map[string] int
16、添加了類型推導 var a int =1 等價 a:=1
var v1 int = 10 // 正確的使用方式1
var v2 = 10 // 正確的使用方式2,編譯器可以自動推導出v2的類型
v3 := 10 // 正確的使用方式3,編譯器可以自動推導出v3的類型
出現在:=左側的變量不應該是已經被聲明過的,否則會導致編譯錯誤,比如下面這個
寫法:
var i int
i := 2
會導致類似如下的編譯錯誤:
no new variables on left side of :=
17、支持多重賦值,i, j = j, i 兩個值可以如此簡單的進行交換 而不許引入外部變量
18、
我們在使用傳統的強類型語言編程時,經常會出現這種情況,即在調用函數時為了獲取一個
值,卻因為該函數返回多個值而不得不定義一堆沒用的變量。在Go中這種情況可以通過結合使
用多重返回和匿名變量來避免這種丑陋的寫法,讓代碼看起來更加優雅。
假設GetName()函數的定義如下,它返回3個值,分別為firstName、lastName和
nickName:
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
若只想獲得nickName,則函數調用語句可以用如下方式編寫: _, _, nickName := GetName()
這種用法可以讓代碼非常清晰,基本上屏蔽掉了可能混淆代碼閱讀者視線的內容,從而大幅
降低溝通的復雜度和代碼維護的難度
19、
在Go語言中,常量是指編譯期間就已知且不可改變的值。常量可以是數值類型(包括整型、
浮點型和復數類型) 、布爾類型、字符串類型等。
所謂字面常量(literal) ,是指程序中硬編碼的常量,如:
-12
3.14159265358979323846 // 浮點類型的常量
3.2+12i // 復數類型的常量
true // 布爾類型的常量
"foo" // 字符串常量
在其他語言中,常量通常有特定的類型,比如?12在C語言中會認為是一個int類型的常量。
如果要指定一個值為?12的long類型常量,需要寫成-12l,這有點違反人們的直觀感覺。Go語言
的字面常量更接近我們自然語言中的常量概念,它是無類型的。只要這個常量在相應類型的值域
范圍內,就可以作為該類型的常量,比如上面的常量-12,它可以賦值給int、uint、int32、
int64、float32、float64、complex64、complex128等類型的變量。
20、常量的定義
通過const關鍵字,你可以給字面常量指定一個友好的名字:
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 無類型浮點常量
const (
size int64 = 1024
eof = -1 // 無類型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重賦值
const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo", 無類型整型和字符串常量
Go的常量定義可以限定常量類型,但不是必需的。如果定義常量時沒有指定類型,那么它
與字面常量一樣,是無類型常量。
常量定義的右值也可以是一個在編譯期運算的常量表達式,比如
const mask = 1 << 3
由于常量的賦值是一個編譯期行為, 所以右值不能出現任何需要運行期才能得出結果的表達
式,比如試圖以如下方式定義常量就會導致錯誤
const Home = os.GetEnv("HOME")
原因很簡單,os.GetEnv()只有在運行期才能知道返回結果,在編譯期并不能確定,所以
無法作為常量定義的右值。
21、
Go語言預定義了這些常量:true、false和iota。
iota比較特殊,可以被認為是一個可被編譯器修改的常量,在每一個const關鍵字出現時被
重置為0,然后在下一個const出現之前,每出現一次iota,其所代表的數字會自動增1。
從以下的例子可以基本理解iota的用法:
const ( // iota被重設為0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota在每個const開頭被重設為0)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0
iota比較特殊,可以被認為是一個可被編譯器修改的常量,在每一個const關鍵字出現時被
重置為0,然后在下一個const出現之前,每出現一次iota,其所代表的數字會自動增1。
從以下的例子可以基本理解iota的用法:
const ( // iota被重設為0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota在每個const開頭被重設為0)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0
v float64 = iota * 42 // v == 42.0
w = iota * 42 // w == 84
w = iota * 42 // w == 84
)
const x = iota // x == 0 (因為iota又被重設為0了)
const y = iota // y == 0 (同上)
如果兩個const的賦值語句的表達式是一樣的,那么可以省略后一個賦值表達式。因此,上
面的前兩個const語句可簡寫為:
const ( // iota被重設為0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 <<iota // a == 1 (iota在每個const開頭被重設為0)
b // b == 2
c // c == 4
)
22、 關于枚舉 所有符號 以大寫開頭在包外是可見的 小寫只能在包內部使用
枚舉指一系列相關的常量,比如下面關于一個星期中每天的定義。通過上一節的例子,我們
看到可以用在const后跟一對圓括號的方式定義一組常量, 這種定義法在Go語言中通常用于定義
枚舉值。Go語言并不支持眾多其他語言明確支持的enum關鍵字。
下面是一個常規的枚舉表示法,其中定義了一系列整型常量:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 這個常量沒有導出
)
同Go語言的其他符號(symbol)一樣,以大寫字母開頭的常量在包外可見。
以上例子中numberOfDays為包內私有,其他符號則可被其他包訪問。
23、go中的布爾類型 只能用 false true != ==不能進行強制轉換
Go語言中的布爾類型與其他語言基本一致,關鍵字也為bool,可賦值為預定義的true和
false示例代碼如下:
var v1 bool
v1 = true
v2 := (1 == 2) // v2也會被推導為bool類型
布爾類型不能接受其他類型的賦值,不支持自動或強制的類型轉換。以下的示例是一些錯誤
的用法,會導致編譯錯誤:
var b bool
b = 1 // 編譯錯誤
b = bool(1) // 編譯錯誤
以下的用法才是正確的:
var b bool
b = (1!=0) // 編譯正確
fmt.Println("Result:", b) // 打印結果為Result: true
24、Go語言支持以下的幾種比較運算符:>、<、==、>=、<=和!=。這一點與大多數其他語言相 同,與C語言完全一致。
if i!=j { } //必須帶大括號
i,j:=1,2
if i==j{
fmt.Println("i==j");
}else {
fmt.Println("i!=j");
}
25、兩個不同類型的值不能比較 比如 int8 int16,只能強制轉換 然后再做比較
var a int8
var b int16
a,b=1,2
if int16(a)==b{
fmt.Printf("a==b")
}
26、雖然兩個 int8 int16不能直接比較 但是 任何整數類型都能和字面常量整數進行比較 ,但是不能和字符串字面常量進行比較
var a int16
if a==1{
fmt.Printf("a!=\"a\"");
}
27、Go語言中的位運算 注意 C語言中的~ 取反。 而Go中變成了^
Go語言支持表2-2所示的位運算符。
表 2-2
運 算 含 義 樣
例
x << y 左移 124
<< 2 // 結果為496
x >> y 右移 124
>> 2 // 結果為31
x ^ y 異或 124
^ 2 // 結果為126
x & y 與
124 & 2 // 結果為0
x | y 或 124
| 2 // 結果為126
^x 取反 ^2
// 結果為-3
Go語言的大多數位運算符與C語言都比較類似,除了取反在C語言中是~x,而在Go語言中 是^x
28、關于浮點數的操作 浮點數 自動推導 是float64即C語言中的double 不能直接和fload32轉換 要進行強制轉換
因為浮點數的比較精度
浮點型用于表示包含小數點的數據,比如1.234就是一個浮點型數據。Go語言中的浮點類型
采用IEEE-754標準的表達方式。
1. 浮點數表示
Go語言定義了兩個類型float32和float64,其中float32等價于C語言的float類型,
float64等價于C語言的double類型。
在Go語言里,定義一個浮點數變量的代碼如下:
var fvalue1 float32
fvalue1 = 12
fvalue2 := 12.0 // 如果不加小數點,fvalue2會被推導為整型而不是浮點型
對于以上例子中類型被自動推導的fvalue2,需要注意的是其類型將被自動設為float64,
而不管賦給它的數字是否是用32位長度表示的。因此,對于以上的例子,下面的賦值將導致編譯
錯誤:
fvalue1 = fvalue2
采用IEEE-754標準的表達方式。
1. 浮點數表示
Go語言定義了兩個類型float32和float64,其中float32等價于C語言的float類型,
float64等價于C語言的double類型。
在Go語言里,定義一個浮點數變量的代碼如下:
var fvalue1 float32
fvalue1 = 12
fvalue2 := 12.0 // 如果不加小數點,fvalue2會被推導為整型而不是浮點型
對于以上例子中類型被自動推導的fvalue2,需要注意的是其類型將被自動設為float64,
而不管賦給它的數字是否是用32位長度表示的。因此,對于以上的例子,下面的賦值將導致編譯
錯誤:
fvalue1 = fvalue2
對于以上例子中類型被自動推導的fvalue2,需要注意的是其類型將被自動設為float64,
而不管賦給它的數字是否是用32位長度表示的。因此,對于以上的例子,下面的賦值將導致編譯
錯誤:
fvalue1 = fvalue2
而必須使用這樣的強制類型轉換:
fvalue1 = float32(fvalue2)
29、自定義精準的 浮點數比較 ,由于浮點數不是一種精確的表達方式 所以比較精度 可能不準確
因為浮點數不是一種精確的表達方式, 所以像整型那樣直接用==來判斷兩個浮點數是否相等
是不可行的,這可能會導致不穩定的結果。
下面是一種推薦的替代方案:
import "math"
// p為用戶自定義的比較精度,比如0.00001
func IsEqual(f1, f2, p float64) bool {
return math.Fdim(f1, f2) < p
}
30、 Go語言中的復數類型 , real 取出 實部 imag取出虛部 虛部為0 的復數 為純虛數。 某一類數字可以表示成這種復數類型
var v1 complex64
v1 = 2.5+15i
v2 := 2.5+15i
v3 :=complex(2.5,15)
fmt.Println(v1)
fmt.Println(v2)
fmt.Println(v3)
fmt.Println("real:",real(v1))
fmt.Println("real:",imag(v1))
復數實際上由兩個實數(在計算機中用浮點數表示)構成,一個表示實部(real),一個表示虛部(imag)。
對于什么是復數可以參考:http://baike.baidu.com/view/10078.htm
復數實際上由兩個實數(在計算機中用浮點數表示)構成,一個表示實部(real) ,一個表示
虛部(imag) 。如果了解了數學上的復數是怎么回事,那么Go語言的復數就非常容易理解了。
1. 復數表示
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
復數表示的示例如下:
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
var value1 complex64
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
// 由2個float32構成的復數類型
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
value1 = 3.2 + 12i
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
value2 := 3.2 + 12i
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
// value2是complex128類型
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
value3 := complex(3.2, 12)
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
// value3結果同 value2
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
2. 實部與虛部
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
對于一個復數z = complex(x, y),就可以通過Go語言內置函數real(z)獲得該復數的實
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
部,也就是x,通過imag(z)獲得該復數的虛部,也就是y。
</p>
<p style="font-family:'Microsoft Yahei',Tahoma,Arial,SimSun,'Hiragino Sans GB',PMingLiu,Verdana,sans-serif;font-size:13px;background-color:#F9F9F9;">
更多關于復數的函數,請查閱math/cmplx標準庫的文檔。
</p>
</div>
31、Golang中的字符串操作
go中的字符串聲明之后只能獲取 字符不能修改字符 但是可以修改整個字符串
var str string
str = "abc"
str += "d"
str="1111"
fmt.Println(str)
我們可以獲取單個字符但是不能修改單個字符
var str string
str = "abc"
str += "d"
ch:=str[0]
fmt.Printf("A:%c",ch) //println不能格式化
32、關于Go的編碼處理 只支持 Unicode UTF-8格式
import strings 這個包中包含了處理string類型的所有工具函數函數
Go編譯器支持UTF-8的源代碼文件格式。這意味著源代碼中的字符串可以包含非ANSI的字
符,比如“Hello world. 你好,世界! ”可以出現在Go代碼中。但需要注意的是,如果你的Go代
碼需要包含非ANSI字符,保存源文件時請注意編碼格式必須選擇UTF-8。特別是在Windows下一
般編輯器都默認存為本地編碼,比如中國地區可能是GBK編碼而不是UTF-8,如果沒注意這點在
編譯和運行時就會出現一些意料之外的情況。
字符串的編碼轉換是處理文本文檔(比如TXT、XML、HTML等)非常常見的需求,不過可
惜的是Go語言僅支持UTF-8和Unicode編碼。對于其他編碼,Go語言標準庫并沒有內置的編碼轉
換支持。不過,所幸的是我們可以很容易基于iconv庫用Cgo包裝一個。這里有一個開源項目:
https://github.com/xushiwei/go-iconv
符,比如“Hello world. 你好,世界! ”可以出現在Go代碼中。但需要注意的是,如果你的Go代
碼需要包含非ANSI字符,保存源文件時請注意編碼格式必須選擇UTF-8。特別是在Windows下一
般編輯器都默認存為本地編碼,比如中國地區可能是GBK編碼而不是UTF-8,如果沒注意這點在
編譯和運行時就會出現一些意料之外的情況。
字符串的編碼轉換是處理文本文檔(比如TXT、XML、HTML等)非常常見的需求,不過可
惜的是Go語言僅支持UTF-8和Unicode編碼。對于其他編碼,Go語言標準庫并沒有內置的編碼轉
換支持。不過,所幸的是我們可以很容易基于iconv庫用Cgo包裝一個。這里有一個開源項目:
https://github.com/xushiwei/go-iconv
33、在Go中字符串的單個字符就是 byte類型也就是 uint8
一個字符串的長度len返回的默認是int類型也就是平臺相關類型,我們在做相應的操作的收 要么自動推導 要么進行強制轉換
var str string
str = "abcdefghijklmn"
var length int8=int8(len(str))
for i:=0 ;i<int(length) ;i++{
fmt.Printf("%c",str[i])
}
34、關于遍歷Unicode字符,每個 unicode的字符類型是 rune
每個中文字符在UTF-8中占3個字節,而不是1個字節。
另一種是以Unicode字符遍歷:
str := "Hello,世界"
for i, ch := range str {
fmt.Println(i, ch)//ch的類型為rune
}
輸出結果為:
0 72
1 101
2 108
3 108
4 111
5 44
6 32
7 19990
10 30028
以Unicode字符方式遍歷時,每個字符的類型是rune(早期的Go語言用int類型表示Unicode
字符) ,而不是byte。
測試代碼
package main
import "fmt"
func main() {
var strUnicode string = "hello,世界"
for i,ch := range strUnicode{
fmt.Println(i,ch)
}
}
35、關于 Go語言中支持的兩種字符類型 一種是 byte 實際上是uint8的別名 ,另一種是unicode類型的字符 關鍵字為 rune
在Go語言中支持兩個字符類型,一個是byte(實際上是uint8的別名) ,代表UTF-8字符串的單個字節的值;另一個是rune,代表單個Unicode字符。
關于rune相關的操作,可查閱Go標準庫的unicode包。另外unicode/utf8包也提供了 UTF8和Unicode之間的轉換。
出于簡化語言的考慮,Go語言的多數API都假設字符串為UTF-8編碼。盡管Unicode字符在標 準庫中有支持,但實際上較少使用。
36、遍歷unicode字符的另一種是 可以用變量占位符去掉不想要的數據
package main
import "fmt"
func main() {
var strUnicode string = "hello,世界"
for _,ch := range strUnicode{
fmt.Printf("%c\n",ch)
}
}
37、關于Go語言的指針操作
package main
import "fmt"
func main() {
var inta int8=3 ;
var pinta*int8=&inta ;
fmt.Printf("%d",*pinta);
}
38、
關于數組的遍歷 range 遍歷可以選擇忽略 索引
package main
import "fmt"
func main() {
byteArr:=[5]byte{1,2,3,4,5}
for _,val:=range byteArr {
fmt.Println(val)
}
}
//////////////////////////////////各種數組的聲明/////////////////////////////////
[32]byte // 長度為32的數組,每個元素為一個字節
[2*N] struct { x, y int32 } // 復雜類型數組
[1000]*float64
// 指針數組 [3][5]int
// 二維數組 [2][2][2]float64
// 等同于[2]([2]([2]float64))
/////關于二維數組的初始化以及聲明..................................
package main
import "fmt"
func main() {
td:=[2][5]int{{1,2,3,4,5},{5,4,3,2,1}}
for _,val:=range td{
for _,vall:=range val{
fmt.Println(vall)
}
}
}
39、關于Go的數組 是一個值類型,在做為參數傳遞 或者 做為函數返回的時候 都是 數組的副本,所以不能通過傳遞 數組參數在函數內部 進行修改 。、
package main
import "fmt"
func modify(arr[5]int){
arr[1]=1
fmt.Printf("arr[1]=%d\n",arr[1])
}
func main() {
td:=[5]int{1,2,3,4,5}
modify(td)
for _,val:=range td{
fmt.Println(val)
}
}
//////Go Web
40、Go語言中的數組切片 可以從一個已存在的數組創建 也可以直接手動創建一個數組切片
? 一個指向原生數組的指針;
? 數組切片中的元素個數;
? 數組切片已分配的存儲空間。
從底層實現的角度來看,數組切片實際上仍然使用數組來管理元素,因此它們之間的關系讓
C++程序員們很容易聯想起STL中std::vector和數組的關系。基于數組,數組切片添加了一系
列管理功能,可以隨時動態擴充存放空間,并且可以被隨意傳遞而不會導致所管理的元素被重復
基于數組創建切片
package main
import "fmt"
func modify(arr[]int){
arr[1]=1
fmt.Printf("arr[1]=%d\n",arr[1])
}
func main() {
td:=[]int{1,2,3,4,5}
//基于數組創建切片
slice:=td[:3] // td[:] td[begin:end] 都可以創建數組切片 還可以創建一個比數組還大的切片
for _,val:=range slice{
fmt.Println(val)
}
}
41、主動創建數組切片 操作數組 所有的方法 都是適用于數組切片 ,合理利用切片能極大提高內存操作的速度
數組切片支持內建的cap()函數和len()函數
從數組切片創建數組切片的時候只要不超過模板切片的大小那么創建是沒問題的,否則會報出數組切片越界的錯誤。
td:=[]int{1,2,3,4,5} //這樣創建出來的實際上是數組切片
數組切片做為參數傳遞給函數是可以被修改值的 ,解決了Go中數組屬于值類型 結果函數傳遞參數的時候值被復制
package main
import "fmt"
func modify(arr[]int){
arr[1]=1
fmt.Printf("arr[1]=%d\n",arr[1])
}
func main() {
td:=[]int{1,2,3,4,5}
//基于數組創建切片
slice:=td[:3] //從切片創建切片 都可以
modify(slice)
for _,val:=range slice{
fmt.Println(val)
}
}
從輸出結果我們發現了 數組切片可以作為參數傳遞到函數中并且被函數所修改
并非一定要事先準備一個數組才能創建數組切片。Go語言提供的內置函數make()可以用于
靈活地創建數組切片。下面的例子示范了直接創建數組切片的各種方法。
創建一個初始元素個數為5的數組切片,元素初始值為0:
mySlice1 := make([]int, 5)
創建一個初始元素個數為5的數組切片,元素初始值為0,并預留10個元素的存儲空間:
mySlice2 := make([]int, 5, 10)
直接創建并初始化包含5個元素的數組切片:
mySlice3 := []int{1, 2, 3, 4, 5}
當然,事實上還會有一個匿名數組被創建出來,只是不需要我們來操心而已。
數組切片支持Go語言內置的cap()函數和len()函數,代碼清單2-2簡單示范了這兩個內置
函數的用法。可以看出,cap()函數返回的是數組切片分配的空間大小,而len()函數返回的是
數組切片中當前所存儲的元素個數
動態創建 一個 初始化五個0 并且 內存儲空間初始化20的 數組切片
td1:=make([]int,5,20)
fmt.Println(cap(td1))
fmt.Println(len(td1))
//為數組切片動態增加元素
append(td1,1,2,3,4,56,6,7)
//為數組元素添加數組切片
append(td1,td2...) //一定要加... 附加數組切片的時候
需要注意的是,我們在第二個參數mySlice2后面加了三個點,即一個省略號,如果沒有這個省
略號的話,會有編譯錯誤,因為按append()的語義,從第二個參數起的所有參數都是待附加的
元素。因為mySlice中的元素類型為int,所以直接傳遞mySlice2是行不通的。加上省略號相
當于把mySlice2包含的所有元素打散后傳入
42. 數組切片支持內容復制
數組切片支持Go語言的另一個內置函數copy(),用于將內容從一個數組切片復制到另一個
數組切片。如果加入的兩個數組切片不一樣大,就會按其中較小的那個數組切片的元素個數進行
復制。下面的示例展示了copy()函數的行為:
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只會復制slice1的前3個元素到slice2中
copy(slice1, slice2) // 只會復制slice2的3個元素到slice1的前3個位置
old:=[]int{1,2,3,4,5,6}
newSlice:=[]int{1,3,3}
copy(old,newSlice)
fmt.Println(old)
43、在map中使用復雜數據類型
我們可以使用Go語言內置的函數make()來創建一個新map。下面的這個例子創建了一個鍵
類型為string、值類型為PersonInfo的map:
myMap = make(map[string] PersonInfo)
也可以選擇是否在創建時指定該map的初始存儲能力,下面的例子創建了一個初始存儲能力
為100的map:
myMap = make(map[string] PersonInfo, 100)
關于存儲能力的說明,可以參見2.3.6節中的內容。
創建并初始化map的代碼如下:
myMap = map[string] PersonInfo{
"1234":
PersonInfo{"1", "Jack", "Room 101,..."},
}
package main
import "fmt"
type Info struct{
name string
age int8
}
func main() {
var infoMap map[string] Info
infoMap=make(map[string] Info)
infoMap["s1"]= Info{"ydw",11}
infoMap["s2"]=Info{"xxx",22}
fmt.Println(infoMap)
/////如果sone 沒有查找到那么返回值應該是nil 實際上我們只需要判斷 ok是否是 true or false 即可判斷元素是否查找到
sone,ok:=infoMap["s1"]
if ok {
fmt.Println("s1 student info exists!",sone.name,":",sone.age)
}else{
fmt.Println("s1 student info not exists!")
}
}
/////刪除一個map用
delete(map,"key")
Go語言提供了一個內置函數delete(),用于刪除容器內的元素。下面我們簡單介紹一下如
何用delete()函數刪除map內的元素:
delete(myMap, "1234")
上面的代碼將從myMap中刪除鍵為“1234”的鍵值對。如果“1234”這個鍵不存在,那么這個調
用將什么都不發生,也不會有什么副作用。但是如果傳入的map變量的值是nil,該調用將導致
程序拋出異常(panic)
44、對于函數的返回值的限制
func returnFunc(num int) int{
if num > 0 {
return 100 //錯誤 返回值不能寫在if...else之中結構之中
}
return 100
}
45、switch case default用法
switch i {
case 0:
fmt.Printf("0")
case 1:
fmt.Printf("1")
case 2:
fallthrough
case 3:
fmt.Printf("3")
case 4, 5, 6:
fmt.Printf("4, 5, 6")
default:
fmt.Printf("Default")
}
46、Go語言的goto 和break Label更加的靈活處理 循環和跳轉
47、自定義復雜數據類型
type Info struct{
name string
age int8
}
48、關于函數返回 一個值和函數返回多個值
package main
import "fmt"
func ret1() int{
return 1
}
func ret2()(a int,b int){
a,b=1,2
return
}
func main() {
a,b:=ret2()
fmt.Println(ret1(),a,b)
}
48、Go的大小寫規則
Go牢記這樣的規則:小寫字母開頭的函數只在本包內可見,大寫字母開頭的函數才
能被其他包使用。
這個規則也適用于類型和變量的可見性。
49、函數的不定參數 實際上是一種"語法糖"
package main
import "fmt"
func show(args ...int){
for _,val:= range args{
fmt.Println(val)
}
}
func main() {
show(1,2,3)
}
50、不定參數的傳遞 不定參數還可以傳遞給其他不定參數的 函數 并且可以打亂傳遞
...
unc myfunc(args ...int) {
// 按原樣傳遞
myfunc3(args...)
// 傳遞片段,實際上任意的int slice都可以傳進去
myfunc3(args[1:]...)
}
51、// ... 傳遞任意類型的參數
package main
import "fmt"
func Printfx(args ...interface{}) {
for _,val:= range args{
fmt.Println(val)
}
}
func main() {
Printfx(1,2,3,"adsd","sdaddf")
}
52、Go的不定參數語法糖
Go的不定參數語法糖會把 參數構成一個數組切片 當然你直接傳遞 切片數組是不可以的,因為他的參數就是1,2,3,4,5,66,7, 但是我們可以通過...的方式打亂
數組 或者數組切片
...只可以打亂數組切片,常規數組是個值類型你是無法操作的
package main
import "fmt"
func show(args ...int){
for _,val:= range args{
fmt.Println(val)
}
}
// ...
func Printfx(args ...interface{}) {
for _,val:= range args{
fmt.Println(val)
}
}
func main() {
Printfx(1,2,3,"adsd","sdaddf")
slice:=[]int{5,4,3,2,6,7,8}
show(slice...)
}
53、通過傳遞不定參數獲取 任意類型不定參數的類型
package main
import "fmt"
func checkType(args...interface{}){
for _,val:=range args{
switch val.(type){
case int :
fmt.Println("Type is int!")
case string:
fmt.Println("Type is string!")
default:
fmt.Println("Type is unknow!")
}
}
}
func main() {
checkType(1,2,3,"aaaa",int64(22))
}
54、使用匿名函數和閉包 Go的匿名函數實際上就是閉包
///定義匿名函數 并且調用
funAdd:=func(a,b int)int{
return a+b
}
r:=funAdd(11,22)
fmt.Println("a+b=",r)
////定義 +調用匿名函數 一起
r=func(a,b int)int{
return a-b
}(11,2)
fmt.Println("a+b=",r)
////Go閉包 通過函數創建匿名函數 并且返回函數
package main
import "fmt"
func createFunc()(func(aa,bb,cc int) int){
return func(aa,bb,cc int)int{
return aa+bb+cc
}
}
func main() {
add:=createFunc()
addNum:=add(1,2,3)
fmt.Println("addNum:",addNum)
}
package main
import (
"fmt"
)
///////函數的閉包定義 直接調用 .......閉包內部使用的代碼塊外部的變量 只要代碼塊沒有釋放那么變量不會被釋放的
func main() {
var j int = 5
a := func()(func()) {
var i int = 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}()
a()
j *= 2
a()
}
55、函數多返回值
func ret()(int,int){
return 1,2
}
a,b:=ret()
fmt.Println("a,b=",a,b)
56、對于結構類型空的值是nil
57、定義結構體一定要加 type,type和C/C++的 typedef 類似也可以
起別名
package main
import "fmt"
type Data struct{
name string
age int
}
func main() {
data:=Data{"a",1}
fmt.Println(data)
}
///////////////////給結構體起個別名
package main
import "fmt"
type Data struct{
name string
age int
}
type DData Data
func main() {
data:=DData{"a",1}
fmt.Println(data)
}
58、Go的defer和資源釋放 相關問題 defer語句是按照 先進后出的原則,也就是說最后一個defer將會被先執行。
defer字面的意思是延遲執行,也就是說會在不需要的時候自動執行
而Go語言使用defer
關鍵字簡簡單單地解決了資源何時釋放的問題,比如以下的例子:
func CopyFile(dst, src string) (w int64, err error) {
srcFile, err := os.Open(src)
if err != nil {
return
}
defer srcFile.Close()
dstFile, err := os.Create(dstName)
if err != nil {
return
}
defer dstFile.Close()
return io.Copy(dstFile, srcFile)
}
即使其中的Copy()函數拋出異常,Go仍然會保證dstFile和srcFile會被正常關閉。
如果覺得一句話干不完清理的工作,也可以使用在defer后加一個匿名函數的做法:
defer func() {
// 做你復雜的清理工作
} ()
另外,一個函數中可以存在多個defer語句,因此需要注意的是,defer語句的調用是遵照
先進后出的原則,即最后一個defer語句將最先被執行。只不過,當你需要為defer語句到底哪
個先執行這種細節而煩惱的時候,說明你的代碼架構可能需要調整一下了
59、panic()和recover()
////panic場景1
package main
import "fmt"
func main() {
defer func(){
fmt.Println("hello,defer go")
}()
panic(11111)
}
<div style="color:#000000;font-size:14px;">
<span style="color:#ff0000;background-color:inherit;">////recover場景2 </span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;">package main</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;">import "fmt"</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;">func main() {</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;"> defer func(){</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;"> fmt.Println("hello,defer go")</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;"> }()</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;"> panic(11111)</span></span> </div>
<div style="color:#000000;font-size:14px;">
<span style="background-color:inherit;"><span style="color:#ff0000;background-color:inherit;">}</span></span> </div>
</div>
Go語言引入了兩個內置函數panic()和recover()以報告和處理運行時錯誤和程序中的錯
誤場景:
func panic(interface{})
func recover() interface{}
當在一個函數執行過程中調用panic()函數時,正常的函數執行流程將立即終止,但函數中
之前使用defer關鍵字延遲執行的語句將正常展開執行,之后該函數將返回到調用函數,并導致
逐層向上執行panic流程,直至所屬的goroutine中所有正在執行的函數被終止。錯誤信息將被報
告,包括在調用panic()函數時傳入的參數,這個過程稱為錯誤處理流程。
從panic()的參數類型interface{}我們可以得知,該函數接收任意類型的數據,比如整
型、字符串、對象等。調用方法很簡單,下面為幾個例子:
panic(404)
panic("network broken")
panic(Error("file not exists"))
recover()函數用于終止錯誤處理流程。一般情況下,recover()應該在一個使用defer
關鍵字的函數中執行以有效截取錯誤處理流程。如果沒有在發生異常的goroutine中明確調用恢復
過程(使用recover關鍵字) ,會導致該goroutine所屬的進程打印異常信息后直接退出。
以下為一個常見的場景。
我們對于foo()函數的執行要么心里沒底感覺可能會觸發錯誤處理,或者自己在其中明確加
入了按特定條件觸發錯誤處理的語句,那么可以用如下方式在調用代碼中截取recover():
defer func() {
if r := recover(); r != nil {
log.Printf("Runtime error caught: %v", r)
}
}()
foo()
無論foo()中是否觸發了錯誤處理流程,該匿名defer函數都將在函數退出時得到執行。假
如foo()中觸發了錯誤處理流程,recover()函數執行將使得該錯誤處理過程終止。如果錯誤處
理流程被觸發時,程序傳給panic函數的參數不為nil,則該函數還會打印詳細的錯誤信息。
60、panic()函數和recover()函數的調用具體區別在哪里
在panic()開始錯誤處理流程,傳入的類型是interface{}任意類型 , 如果我們在defer 函數中調用
recover()函數那么會打斷錯誤處理流程。 panic的調用會終止正常的程序流程
recover()函數用于終止錯誤處理流程。一般情況下,recover()應該在一個使用defer
關鍵字的函數中執行以有效截取錯誤處理流程。如果沒有在發生異常的goroutine中明確調用恢復
過程(使用recover關鍵字) ,會導致該goroutine所屬的進程打印異常信息后直接退出。
package main
import "fmt"
func main() {
//通過閉包定義 defer匿名函數 并且直接調用
defer func(){
//recover 結束當前錯誤處理過程 并且返回 panic的參數,并不結束其他goroutine的執行.......
if r:=recover() ;r!=nil{
fmt.Println("recover() called!")
}
fmt.Println("hello,defer go")
}()
panic("hello,go")
}
61、關于const 和iota的使用
package main
import "fmt"
var str string="aaa"
const(
A=iota
B
C
)
func main() {
fmt.Println(B)
defer func(){
if r:=recover() ;r!=nil{
fmt.Println("recover() called!")
fmt.Println(r)
}
fmt.Println("hello,defer go")
}()
panic("hello,go")
}
62、快速排序算法與數組切片的使用
package main
import "fmt"
import "math/rand"
/////冒泡排序Go實現 時間復雜富 O(n)=n~n^2
func bubbledSort(values []int){
var flags bool =true
for i:=0 ;i<len(values);i++{
flags=true
for j:=0;j<len(values)-i-1;j++{
if values[j]>values[j+1] {
values[j],values[j+1]=values[j+1],values[j]
flags=false
}
}
if flags {
break
}
}
}
///////快速排序Go實現
func quickSort(values []int,left,right int){
temp := values[left]
p := left
i, j := left, right
for i <= j {
for j >= p && values[j] >= temp {
j--
}
if j >= p {
values[p] = values[j]
p = j
}
if values[i] <= temp && i <= p {
i++
}
if i <= p {
values[p] = values[i]
p = i
}
}
values[p] = temp
if p - left > 1 {
quickSort(values, left, p - 1)
}
if right - p > 1 {
quickSort(values, p + 1, right)
}
}
func main() {
//創建初始化0個元素 容量1000的 切片 如果用索引直接訪問切片會越界的 容量必須大于等于 初始化元素個數
//val[1]=11
val:=make([]int,0,1000)
for i:=0;i<1000;i++{
val=append(val,rand.Intn(1000))
}
fmt.Println("冒泡排序前:",val)
bubbledSort(val)
fmt.Println("冒泡排序后:",val)
}
63、Go中的import和package 等等的關系
//import只是引入的文件夾而已,,,可以使用相對路徑或者絕對路徑
//他會把文件夾中的所有.go文件引入 ,,,,,,
///package xx 實際上是 在外不用調用用的 比如xx.A() 并不是給import使用 package內部的小寫全部是私有 大寫全部是公有
//外部包不能和主模塊放到一起會編譯不過的
import "./bubble"
來自:http://blog.csdn.net/yue7603835/article/details/44264925
本文由用戶 y37f 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!