更新:
進程有自己獨立的堆和棧,不共享堆和棧。
線程有自己獨立的棧和共享的堆,不共享棧。
協程和線程一樣共享堆,不共享棧。協程有程序員在協程的代碼裏顯示調度。
執行協程只需要極少的棧內存(大概是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