GO超詳細基礎語法&黑點

更新:
進程有自己獨立的堆和棧,不共享堆和棧。
線程有自己獨立的棧和共享的堆,不共享棧。
協程和線程一樣共享堆,不共享棧。協程有程序員在協程的代碼裏顯示調度。

執行協程只需要極少的棧內存(大概是4~5KB),默認情況下,線程棧的大小爲1MB。

最新更新

GO的黑點

GC1.0在32位環境下有重大缺陷,導致整個進程停頓嚴重。只能減少進程中的對象,將它的間歇性停頓控制在可接受範圍內。

禁止未使用變量和多餘import,存在則編譯錯誤,如import某數據庫驅動的pkg,刪掉編譯通過但是運行時必然報錯,找不到數據庫驅動。

創建對象的方式太多令人糾結

defer的語義定義設定不夠合理
有無限循環語句不停地創建資源,defer語句得不到執行
系統存儲defer列表也要格外佔用資源

defer設定在所屬代碼塊結束時執行,更好

沒有泛型支持
list,set這些常見的數據類型的接口,放進去的對象是一個具體的類型,取出來只能是無類型的interface{},得強制類型之後才能繼續使用

實現接口不需要明確聲明
http://blog.zhaojie.me/2013/04/why-i-dont-like-go-style-interface-or-structural-typing.html

靜態編譯的文件尺寸很大


complex浮點數
rune(32位)4個字節 ,相當於C 語言的Char
變量類型寫在變量名之後
函數返回類型也寫在方法最後,如fun grade( score int) string{}
var a=可以寫作a:=
編譯器自動推測變量類型
原生支持複數
枚舉const(b=iota)(自增)

if條件不需要括號
if可以賦值
if可以把判斷語句寫在;後面

for也不帶括號
初始,結束條件,遞增表達都可以省略

switch自動帶break,後面可以不跟條件判斷
用傳入分數來判斷成績等級
switch score{}的話必須內部是score=XX,來我們內部是grade="A"等等,所以要直接switch

返回兩個值的函數,只想return第一個值:
q,_:=div(a,b)
return q


函數也可以作爲其他函數的參數
沒有默認參數,可選參數,沒有重載
反射:runtime.FuncForPC().Name()
數組:數組名…
i:=range 數組名

GO語言只支持值傳遞(經典的i++不改變輸出值)


數組、切片、容器
arr:=[3]int{1,3,5}這種寫法必須要初始化
for i,v:=range arr3{
fmt.Println(i,v)//同時獲得序號和值
}

[10]int和[20]int是不同類型
調用func f(arr [10] int)打印拷貝後加工過的數組
直接打印原來arr還是原來的那些值
沒有C語言的:數組名就是數組頭指針

切片
arr[:]打印全部
arr[2:6]打印下標2到5
slice改變的東西會一直保持修改後的狀態
slice本身沒有數據,是對底層array的一個view
reslice:slice的slice 即使下標不被包含在二次slice後的內容裏,也能打印出來

slice可以向後擴展
原因:在這裏插入圖片描述

向slice添加元素 如果超越cap,系統會分配更大的底層數組
分配cap由1 2 4一直到128

s :=make([]int,16)
s :=make([]int,16,32)

copy(s2,s1)讓s1替換s2的相應部分
假如要刪除[0 2 4 6 8 0 0 0 0]中的8,用s=append(s[:4],s[4:])
刪除第一個
front:=s[0]
s=s[1:]
刪除隊尾
tail:=s[len(s)-1]
s=s[:len(s)-1]
slice擴容可以參考:
https://www.cnblogs.com/junneyang/p/6074786.html


map定義:map[K]V
複合map:map[K1]map[K2]V
打印順序不是定義順序,是無序的
m:=make(map[string] int)自動初始化爲空
for k,v range m{
fmt.Print(k,v)}

取值
name,ok:=m[K]
fmt.Println(name,ok)//打印名字和true or false

delete(m,“name”)
Java要實現HashCode和Equals才能作爲key

map使用哈希表,必須可以比較相等
除了slice,map,fuction的內建類型都可以作爲key


最長不重複字串
核心函數

for i,ch:=range []byte(s){
   lastI,ok:=lastOccured[ch]//lastI是遍歷的字符的上一次出現過的下標,默認爲0因爲map的V默認沒有內容,Ok代表V是否有內容,也就是是否出現過

   if ok&&lastI>=start {
      start=lastI+1//關鍵要理解這裏的start即最長不重複字串的開頭必須要在上一個出現了的字母的後面
   }
   if i-start+1>maxlength{
      maxlength=i-start+1
   }
   lastOccured[ch]=i
   fmt.Println(ch,lastI,start,ok,maxlength,lastOccured[ch])
}
return maxlength

%X打印字節數,使用utf8.RuneCOuntInString()獲得字符數,len獲得字節數,[]byte獲得字節

其他操作在strings包裏面 fileds join split contains index 等


面向對象:
只支持封裝,不支持繼承和多態
只有struct,沒有class

不論地址還是結構本身, 都用.來訪問成員
局部變量放在堆上還是棧上不需要知道,GC會決定

爲結構定義方法:
接受的參數寫在方法前面的()
func(node *TreeNode)setValue(value int){
node.value=value;
}

接收者,即是任意類型(結構體,指針,接口等)的實例。函數跟類型綁定,即成了方法

只有指針纔可以改變結構內容
nil指針也可以調用方法

遍歷樹:
func(node *treeNode) traverse(){
if node==nil{
return
}

node.left.traverse()
node.print()
node.right.traverse()
}


首字母大寫代表public
首字母小寫代表private
每個目錄只能有一個包
包名可以跟目錄名不一樣

擴充系統類型或用別人的類型:
定義別名
使用組合


面向接口的編程語言,不是面向對象
duck typing。像鴨子走路,像鴨子叫,就是鴨子
描述事物的外部行爲而非內部結構

python
def download(retriever):
return retriever.get("")
//運行時才知道retriever有沒有get
C++
template
string download(const R& retriever){
return retriever.get("")}
//編譯時才知道傳入的retriever有沒有get
java一定要繼承接口 但有時需要兩個接口的功能,java做不到

同時有python的靈活性,又有java的類型檢查


接口由使用者定義
接口必須要有結構體

/* 定義接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
   method_name3 [return_type]
   ...
   method_namen [return_type]
}

/* 定義結構體 */
type struct_name struct {
   /* variables */
}

/* 實現接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
   /* 方法實現 */
}

接口 接口=new (結構體)


defer 在return前把函數執行
defer先進後出
使用的時機:Open/Close,Lock/Unlock,PrintHeader/PrintFooter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章