《一週學會go語言並應用》 by王奇疏php
歡迎加入go語言羣: 218160862 (深圳羣) , 808784562(南寧go語言技術羣) 羣內有實踐
html
點擊加入 (深圳羣),南寧go語言技術羣 808784562,歡迎加入。python
零、安裝go語言,配置環境及IDEmysql
這部份內容很少,請參考個人這篇安裝環境《安裝go語言,配置環境及IDE》 linux
平常只有2條命令:c++
go run 文件路徑/xxx.go 運行go程序
git
go build 文件路徑/xxx.go 編譯爲二進制文件或exe文件
github
若是你不想每次都敲這些命令,附送1個《一鍵編譯go文件命令.bat》 只能windows下使用,( 通常狀況下,ide也是用一樣的原理,ide的運行/編譯也是利用這2個命令集成到ide裏面 )
golang
go build 命令生成的exe文件(或二進制文件)仍是很小的,5M左右。 比c++ c#等要大一些。 這邊是Go的1個ide,叫作liteIde,是中國人寫的,他還寫了1個goqt 界面類庫, 很不錯。sql
第一節、語法
1)註釋: // 單行註釋 /* 多行註釋 *//
2). 【基本語法】
一個go語言程序項目只能有1個 package main包、1個main函數, 像C語言同樣。用 import 關鍵字導入類包。
go語言變量和函數名的首字母大寫,表示公開的意思,至關於類裏面的public屬性修飾。小寫則不公開,別的package包不能引用。
例子:
package main
import "fmt" // fmt是標準包,提供基本的打印函數 Println等,相似於C語言裏面的 #include <stdio.h>
func main( ){ // 大括號不能換行
fmt.Println( "hello world~! go程序,你好。" )
}
go語言代碼不須要以分號結束。類包導入後 和 變量定義後必須使用,否則編譯器報錯。(能夠經過下劃線符號來回避_)
如下開始,爲了省略代碼,這些: package mian main(){ } 就不寫了。 下面例子中的全部散代碼都應該放在 func main(){ ... } 中運行,除了新定義的函數以外。
關於fmt標準包的函數列表,請參考: 《go語言手冊.chm》 builtin 這個內置包,裏面有詳細說明。 go語言手冊1.3.3中文.chm 下載
標準輸入、輸出函數有:
fmt.Printf( ) 這個函數按照C語言的printf() 裏面的參數, 打印變量。
fmt.Println( ) 這個函數能夠 直接打印 【任何變量】,很是好用於調試顯示信息。
func Scanf( format string, a ...interface{}) (n int, err error)
Scanf從標準輸入掃描文本,根據format 參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數。返回成功掃描的條目個數和遇到的任何錯誤。
3). 操做運算符
支持常見的運算符: + - * / %
邏輯運算符: && || == != ! < <= >= >
二進制運算: & | ~ ^ >> << &^
go的特殊運算符: <- 表示接收傳遞的信號
字符串鏈接符是加號: "hello " + " world~! "
賦值運算符: = 和 := (這個是聲明並賦值)
// go語言不支持三元運算符 ? : ,須要本身模擬三元運算符函數。!!! 模擬方法,詳見第二節:常見用法
4). 變量:
go定義變量的時候,是變量名在左邊, 類型在右邊。
var str string = "字符串"
var num int = 10
我想省略 var 和數據類型,寫得更簡短一點,怎麼辦呢?使用類型自動推導,定義並賦值給變量:
str := "字符串"
num := 12
(最經常使用的就是這種。賦值符號 := , 只能在函數的局部變量中使用,不能在函數外的全局變量中使用)
能夠一次定義多個變量
a, b, c, d := 1, 2, 3, 4
特殊變量下劃線,在須要不使用變量的時候用到( python等語言中也有這個特殊的棄用變量 )
i := 10
_ = i
5). 常量:
const a int = 3
const (
b int = 3
c int = 99
)
// 常量中的枚舉. 當使用關鍵字iota 定義常量組中時,返回: 從常量定義處第n個常量開始計數,自增
const (
d int = 3
e // 若是不提供類型和初始值,那麼視做與上1個常量值和類型都相同
i1 = iota // 這個常量是第3個常量,故i1 == 2 ( 從0數起 ) 。關鍵字 iota致使枚舉 從第n-1個常量開始計數
i2 // 等於3
i3 // 等於4
i4 // 等於5
)
// 下面定義一組文件尺寸的單位,從kb到tb
const (
// 下列常量按照表達式進行賦值. 表達式與iota結合時,其下的常量都將按照此表達式進行計算。
b int64 = 1 << (10 * iota) // 這條表達式的值是:1 , 此時 iota == 0 ,並與表達式 1 << ( 10 * 0 ) 結合, 故表示2的0次方,
kb // 這條表達式的值是:1024 , 此時 iota == 1 ,並與表達式 1 << ( 10 * 1 ) 結合, 【故這條表達式表示: 2的10次方】
mb // 這條表達式的值是:1048576, 此時 iota == 2 ,並與表達式 1 << ( 10 * 2 ) 結合, 【故這條表達式表示: 2的20次方】
gb // 這條表達式的值是:1073741824, 此時 iota == 3 ,並與表達式 1 << ( 10 * 3 ) 結合, 【故這條表達式表示: 2的30次方】
tb // 這條表達式的值是:1099511627776, 此時 iota == 4 , 同上 表示: 2的40次方
)
6). 分支 和 循環
go語言的 if 表達式不須要括號:
if true {
fmt.Println( "條件爲真" )
} else{
}
// 在if中賦值,並判斷
if i := 1; i == 1 {
fmt.Println( "條件爲真" )
}
// 在go語言中switch不須要break來終止,會自動跳出。 只有使用 fallthrough 關鍵字的時候纔會繼續往下走。
switch i {
case 0:
fmt.Printf("0")
case 1:
fmt.Printf("1")
case 2:
fallthrough
case 3:
fmt.Printf("3")
default:
fmt.Printf("Default")
}
【循環遍歷】
//通常的for循環
for i := 0; i < 10 ; i++ {
fmt.Println( i )
}
// 1維純數字數組
arr := [...] int { 8, 2, 3, 11, 324, 133, 1, 45, 13, 7, 14 }
for i := 0; i < len( arr ); i++ {
fmt.Println( arr[ i ] )
}
//使用for range 來循環,至關於別的語言foreach( list k=>v )
// 輸出一維索引數組( php中的索引數組,其餘語言中的map, json )
myInfo := map[ string ] string { "id":"1", "name":"王奇疏", "sex":"man", }
for k, v := range myInfo {
fmt.Println( "k=", k, " v=", v )
}
輸出:
id : 1
name : 王奇疏
sex : man
// 輸出二維索引數組( 例如數據庫多行記錄 或 1個json ) 【這是用原始方式實現字典,還有另1種使用struct方式實現字典】
personList := map[ int ]( map[ string ] string ) {
0: {
"name": "李雷",
"sex": "man",
"age": "18",
"birth": "1993-02-18",
},
1: {
"name": "韓梅梅",
"sex": "women",
"age": "19",
"birth": "1992-11-03",
},
2: {
"name": "王奇疏",
"sex": "man",
"age": "???",
"birth": "xxx-01-11",
},
}
for i, person := range personList {
fmt.Printf(
"%d.%s%s今年%s歲,%s\n",
i+1,
person["name"],
ifReturn(person["sex"] == "man", "先生", "女士"),
person["age"],
ifReturn(person["sex"] == "man", "他今晚決定去酒吧", "她今晚去洗頭") )
}
// 模擬三元運算符。 go 不支持三元運算符,須要本身模擬簡化!!! 奇葩.這個使用例子是 str := ifReturn( 0 == 1, "0等於1", "0不等於1" )
func ifReturn( condition bool, trueVal, falseVal interface{} ) interface{} {
if condition {
return trueVal
}
return falseVal
}
輸出
1.李雷先生今年18歲,他今晚決定去酒吧
2.韓梅梅女士今年19歲,她今晚去洗頭
3.王奇疏先生今年???歲,他今晚決定去酒吧
7). 定義函數
func echo( msg string ) {
fmt.Println( msg )
}
// 函數返回值,能夠返回多個值. 參數跟變量同樣
func sum2( a, b int ) ( int, bool ) {
return a + b , true
}
func sum( arr []int ) int { // 返回int型的值
sum := 0
for i := 0; i < len( arr ); i++ {
sum += arr[ i ]
}
return sum
}
調用函數:
arr := [...] int { 8, 2, 3, 11, 324, 133, 1, 45, 13, 7, 14 }
total =: sum( arr )
fmt.Println( total )
// func關鍵字後面能夠跟着括號,爲類型添加方法 給該函數標明所屬的類(面向對象,標明該函數所屬的類),來給該類定義方法. 若是沒有類的類型,則純粹是一個函數.
// 這裏的 obj myClass ,表示給myClass類添加了一個方法。這是面向對象的用法。
func ( obj myClass ) myFun ( str string ) {
}
8). 數據類型
基本類型:
類型 長度 默認值 說明
----------------------------------------------------------
bool 1 false
byte 1 0 uint8
rune 4 0 Unicode Code Point, int32
int,uint 4 8 0 32 或 64 位
int8,uint8 1 0 -128 ~ 127, 0 ~ 255
int16,uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32,uint32 4 0 -21億 ~ 21 億, 0 ~ 42 億
int64,uint64 8 0
float32 4 0.0
float64 8 0.0
complex64 8
complex128 128
string "" UTF-8 字符串
array 值類型
struct 值類型
slice nil 引用類型
map nil 引用類型
channel nil 引用類型
interface nil 用於表示任意類型的數據類型、或者做爲面向對象的【接口】使用
function nil 函數
uintptr 4 或 8 存儲指針的 uint32 或 uint64 整數
空指針值爲 nil
----------------------------------------------------------
數學上支持八進制、十六進制 表示法,以及科學記數法。標準庫 math 定義了各數字類型取值範圍。
a, b, c, d := 071, 0x1F, 1e9, math.MinInt16
請參考《go語言手冊1.3.3中文.chm》 builtin 這個內置包,裏面有數據類型的詳細說明。
須要說明的是:數據類型是嚴格區分的, 數據類型之間只有【互相兼容的類型】才能直接互相賦值,不然:要麼經過強制類型轉換來賦值,要麼須要經過類包來轉換。
例如 這樣會報錯:
var i int = 3
var j int64 = i
_ = j
報錯信息: xxx.go:錯誤所在的行數 : cannot use i (type int) as type int64 in assignment
說明 int 和 int64 不是1個類型。 類型轉換,會在下一節講到。
第二節、常見用法( 類型轉換、經常使用數組、json map字典、使用第三方類庫如mysql )
讓字符串保持原樣,不處理轉義問題,用1個小引號括起來像這樣: str := ` 字符串'"'''''sfsdfsdf `
// go語言不支持三元運算符 ? : ,須要本身模擬三元運算符函數。!!! 奇葩. 這個使用例子是 str := ifReturn( 0 == 1, "0等於1", "0不等於1" )
func ifReturn( condition bool, trueVal, falseVal interface{} ) interface{} {
if condition {
return trueVal
}
return falseVal
}
1).數據類型之間的轉換 ,經常使用的轉換函數
上一節講到: 數據類型是嚴格區分的, 數據類型之間只有【互相兼容的類型】才能直接互相賦值,不然:要麼經過強制類型轉換來賦值,要麼須要經過類包來轉換。
例如: int 和 int64 不是一個類型。
類型轉換的方法, 強制轉換:經過 類型名( ) 這種方式強制轉換
var i int = 123
var j int64 = int64( i )
_ = j // 定義1個變量,但不使用,讓編譯器不報錯的方法
【go類型轉換】
(1). 數據類型是嚴格區分的, go必須顯示調用函數來作類型轉換,沒有隱式轉換的說法。
特別注意 if 條件中只能是bool型,不能是 if 0 之類。 能夠用表達式來處理這類 if exp != 0
例如這是錯誤的:
if 0 == false {
fmt.Println( " 0等於flase嗎?不相等。if中只能使用布爾型進行判斷,不能用 0 空等其它類型的值 與 布爾型進行判斷" )
}
if ! 0 {
fmt.Println( " 這也是錯的" )
}
if中只能使用布爾型進行判斷,不能用 0 空等其它類型的值 與 布爾型進行判斷。
能夠經過轉換爲表達式來處理
res := 1 == 1
if res {
fmt.Println( "這是正確的" )
}
(2). 只有兩種互相兼容的數據類型的變量,纔可使用 類型() 這種方式來進行轉換,不然須要使用類庫 或者 自行處理。
如: int8和int32 是兼容的,可使用 int32( i ) 進行轉換。 相似的還有 float32( ) 、 string( ) 、 []byte( "abc" )
(3). 其它不兼容的數據類型的轉換方法,使用經常使用的類庫進行轉換: fmt.sprintf, strconv.Itoa(i) strconv.Atoi(s) , ParseInt() ParseFloat()等
還有就是 強制類型轉換表達式, 如 _var.( *int32 ) 這種方式也叫作斷言。
fmt.sprintf( ) 將1個變量打印轉換爲字符串
strconv.Itoa(i) 使用字符串轉換類包strconv, Itoa()是表示數字轉成字符串( integer to array )
strconv.Atoi(s) 這個是相反,表示字符串 轉成 數字( array to integer )
ParseInt() ParseFloat() 解釋爲數字、浮點數
(4). 經常使用例子
一、整形到字符串:
var i int = 1
var s string
s = strconv.Itoa(i) 或者 s = FormatInt(int64(i), 10)
二、字符串到整形
var s string = "1"
var i int
i, err = strconv.Atoi(s) 或者 i, err = ParseInt(s, 10, 0)
三、字符串到float(32 / 64)
var s string = 1
var f float32
f, err = ParseFloat(s, 32)
float 64的時候將上面函數中的32轉爲64便可
四、整形到float或者float到整形, 直接使用float(i) 或者 int(f) 直接進行轉換便可
五、 []byte數組 轉爲字符串: string( buf )
str := string( []byte{ 'a','b','c' } ) // byte轉字符串
buf := []byte( "abc" ) // 字符串轉byte
【字符串處理】:
go的字符串支持直接根據索引 index 截取字符串,例如:
str := "hello world"
fmt.Print( str[0:5] ) // 從0到第5字節, 至關於php裏面的 substr( str, 0, 4 )
tmp := fmt.Sprintf("%d", 22221999 )
fmt.Println( tmp[5:] ) //從第6個字節下標開始截取字符串, 至關於php裏面的 substr( str, 5, 長度 )
這個跟python的切片截取是同樣同樣的,關於切片等下數組還會講到。
關於go語言的字符串處理,詳見go語言中文手冊的2個類包: strings 和 strconv ,包括了:Trim Split Join Replace Repeat ToLower ToUpper HasPrefix( php的strpos ) Contains( 包含 ) 、字符串轉義Quote(至關於php中的addslashe之類) 等函數,以及類型轉換函數。建議學習時候,對這2個類包 大概鳥覽一遍。
(5). 類型轉換踩過的坑
(暫略)
2). 經常使用數組、 map字典等操做
前面第一節,語法的時候發過2個例子。
// 1維純數字數組
arr := [...] int { 8, 2, 3, 11, 324, 133, 1, 45, 13, 7, 14 }
for i := 0; i < len( arr ); i++ {
fmt.Println( arr[ i ] )
}
// 輸出一維索引數組( php中的索引數組,其餘語言中的map, json )
myInfo := map[ string ] string { "id":"1", "name":"王奇疏", "sex":"man", }
// 這句聲明,表示 map[ 索引類型 ] 值類型
for k, v := range myInfo {
fmt.Println( "k=", k, " v=", v )
}
輸出:
id : 1
name : 王奇疏
sex : man
數組、切片、map這幾種結構篇幅佔用較多,只須要簡單掌握 初始化定義和 幾個函數便可:len(list), append( ) , cap( ) .
請參考這篇文章學習,相信很快能使用:《go語言的 數組、slice、map使用》
3). 安裝第3方類包/類庫,如mysql類庫。
(1).類包管理
能夠給包起別名,或者在包名前面加1個點號.表示省略包名
package main
import(
"fmt" f
."strconv" // 咱們下面調用的 Itoa() ,其實應該是 strconv.Itoa( 123 )纔對。 可是這裏使用了.號進行省略包名,因此下面就簡單了。(除非包名很長,通常不建議省略)
)
func main( ){
fmt.println( Itoa( 123 ) )
}
(2). 安裝第3方類包/類庫
首先你要找到第三方類包所在的網址, 例如mysql包: http://github.com/go-sql-driver/mysql
分爲自動安裝 和 手動下載 而後安裝。
很簡單,主要是執行2條命令: go get 網址 和 go install 網址 。
詳細步驟和原理只須要10幾行文字說明,請參考 個人這篇文章:《go get安裝第三方包的前提條件和步驟》(對於github來講,須要先安裝 git 工具)
類庫一旦安裝以後,就能夠在代碼中 import xxx類庫來使用了。
3、經常使用類庫
1.時間處理、定時器、隨機數
格式化輸出當前的時間點:
fmt.Println( time.Now().Format("2006-01-02 15:04:05") ) // 這是個奇葩,傳入的值必須是這個時間點, 聽說是go誕生之日, 記憶方法:6-1-2-3-4-5
會輸出當前時間: 2015-12-31 19:32:20 , 你只要在Format( )參數裏面輸入你想要的格式就行。
更多時間處理的內容,參考go手冊: time 包
golang 定時器: 啓動的時候執行一次,之後天天晚上12點執行。 # stevewang • 2015-03-04 17:17
func startTimer( callBack func() ) {
go func() {
for {
// 執行回調函數. 啓動的時候執行一次
callBack()
now := time.Now()
// 計算下一個零點
next := now.Add( time.Hour * 24 )
next = time.Date( next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location() )
t := time.NewTimer( next.Sub(now) )
// 傳遞信號給線程
<- t.C
}
} ()
}
隨機數:
從下面的例子能夠看見,go語言生成隨機數須要2行代碼:
// 播下種子(這裏用時間戳做爲種子), 調用rand.Intn( 最大數字 ) 生成隨機數
rand.Seed(time.Now().Unix())
num := rand.Intn( 100)
fmt.Println( num )
例子:
package main
import(
"fmt"
"time"
"math/rand" // 隨機數所須要使用的包 (go語言的類包不到30個,多翻翻go手冊就熟悉了)
)
func main(){
list := [...][]int{} // 用於存放數據的數組
max := 200 // 隨機數的最大值 0~200
// 生成20組(條) 二維數據
for i := 0 ; i < 20; i++ {
// 播下種子, 生成隨機數
rand.Seed(time.Now().Unix())
n := rand.Intn( max )
// 每條數據 生成隨機N個數字
tmp := []int{}
for j := 0 ; j < n; j++ {
rand.Seed( time.Now().Unix() - int64( j ) )
tmp = append( tmp, rand.Intn( max ) )
}
list[i] = tmp
}
fmt.Println( "list=", list )
}
2.文件讀寫
// 文件讀寫 只須要簡單掌握幾個函數便可:
fp, e := os.Stat(file) // 判斷文件是否存在
// 創建文件函數:
func Create(name string) (file *File, err Error)
func NewFile(fd int, name string) *File
// 打開文件函數:
func Open(name string) (file *File, err Error)
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
// 這行使用追加模式寫入文件,若是文件不存在則建立
fp, err := os.OpenFile( LOGFILE, os.O_CREATE|os.O_APPEND|os.O_RDWR,0660 )
fp.WriteString( " 寫入內容: " )
更詳細更實用的例子,請參考這篇文章《go語言文件操做》以及《go語言手冊》
3.網絡
主要有參考手冊中的 net包,tcp、udp、http等,請參考《go語言編程》
建立http服務器很簡單
func httpServer(){
//設置訪問的路由, 使用回調函數處理
http.HandleFunc("/", sayhelloName)
// 建立http服務器
fp := http.ListenAndServe(":9007",nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
_ = fp
}
// httpServer的回調處理函數
func sayhelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm() //解析參數, 默認是不會解析的
fmt.Println(r.Form) //這些是服務器端的打印信息
fmt.Println("path", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v := range r.Form {
fmt.Println("key:", k)
fmt.Println("val:", strings.Join(v, ""))
}
fmt.Fprintf(w, "Hello astaxie!") //輸出到客戶端的信息
}
4. 數據庫
經過安裝 mysql等數據庫接口,進行操做。參考《go get安裝第三方包的前提條件和步驟》, 而後安裝這個包 http://github.com/go-sql-driver/mysql
5.ui界面
目前go有一些ui界面庫,主要有 goqt(QT跨平臺界面庫)、 walk (只能在win平臺使用)
特色: goqt 因爲qt自己的體積比較大,帶上qt的dll就有15M了,整個軟件打包成exe後 通常超過20M。 優勢是跨平臺、通用,適合大型軟件;
walk 體積很小,通常界面只有5M,但只有win平臺能使用。
兩個庫目前都不是很完善。 須要說的是, golang的IDE之一 liteIde就是用 goqt寫的,liteIde的做者就是 goqt的做者,並且是中國人,感受很是好。
這是用walk編寫的一個桌面軟件。
6. go語言調用windows或者調用C語言。
1. go語言讓windows發出聲音,或者播放音樂的例子:會發出alert警告的聲音
package main
import "syscall" // 藉助syscall這個內置類庫來完成win32調用
func main(){
winSound()
}
// golang 讓windows發出警告的聲音 todo 須要完善播放mp3之類
func winSound( ) {
funInDllFile, err := syscall.LoadLibrary("Winmm.dll") // 調用的dll文件
if err != nil {
print("cant not call : syscall.LoadLibrary , errorInfo :" + err.Error())
}
defer syscall.FreeLibrary(funInDllFile)
// 調用的dll裏面的函數是:
funName := "PlaySound"
// 註冊一長串調用代碼,簡化爲 _win32Fun 變量.
win32Fun, err := syscall.GetProcAddress(syscall.Handle(funInDllFile), funName)
// 經過syscall.Syscall6()去調用win32的xxx函數,由於xxx函數有3個參數,故需取Syscall6才能放得下. 最後的3個參數,設置爲0便可
_, _, err = syscall.Syscall6(
uintptr(win32Fun), // 調用的函數名
3, // 指明該函數的參數數量
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("alert") ) ), // 該函數的參數1. 可經過msdn查找函數名 查參數含義
// SystemStart
uintptr( 0 ), // 該函數的參數2.
uintptr( 0 ), // 該函數的參數3.
0,
0,
0 )
}
2. go語言調用C語言
(暫略)
4、機制
goroutine 協程。
channel 使用消息傳遞機制 來同步和協調線程之間的操做順序。
select 不阻塞處理。
請參考《go語言編程》
// 異常機制: defer的做用是, 在程序退出時(或函數返回時) 執行的表達式的時候出錯,就報錯。
func writeFile( fileName string ){
fp, err := os.OpenFile( LOGFILE, os.O_CREATE|os.O_APPEND|os.O_RDWR,0660 )
defer fp.Close()
}
// go語言實現回調函數、go語言的匿名函數 和 閉包:
func call ( callBack func() ) {
// 執行回調函數.
callBack()
}
func echo ( ){
fmt.Println( "123" )
}
call( echo )
5、go語言的 struct結構體和類,面向對象和 interface{}
1). go語言使用 struct結構體來定義1個類
// 人類對象: 擁有 id、姓名、性別、國籍等屬性
type person struct {
// 人的id、姓名、性別、生日、國籍、 居住地、祖籍
id int32
name string
sex int8
birthDate string
country string
}
// 實例化類/結構體的方法通常有4種: p表示person簡寫
p1 := new( person )
p1.id = 1
p1.name = "王奇疏"
p1.sex = 1
p2 := &person { }
p3 := &person { id:1, name:"王奇疏", sex:1 }
p4 := &person { 1, "王奇疏", 1 }
這4種都是實例化1個對象,在做爲初始化的時候基本能夠通用。 (他們之間也是有差異的, 須要你本身在實際使用中記憶一下。 主要是繼承的時候有初始化的問題,例子3).中有一行註釋提到這個問題。)
2). 面向對象通常有2種封裝方式:繼承和組合,go語言所有使用 組合 的方式來實現面向對象。組合的好處是解耦方便。
下面是給 person類 添加幾個方法: 吃飯、走路、說話、笑 的方法
func ( p person ) eat( food string ){
fmt.Println( p.name, " 吃了 ", food )
}
func ( p person ) walk( ){
fmt.Println( p.name, " 走了一段路 " )
}
func ( p person ) say( msg string ){
fmt.Println( p.name, " 說: " , msg )
}
func ( p person ) laugh( ){
fmt.Println( " LOL ^_^ " , p.name )
}
調用例子:
p4 := &person { id:1, name:"王奇疏", sex:1 }
p4.eat( "一鯨(斤)黑魚" )
3). go語言的繼承 也是使用組合的方式來實現。
接上, 新建1個student類繼承自 person 。
type student struct{
person // go使用組合的方式,將person類當作student的屬性,從這種方式繼承了person類的屬性和方法。
school string
}
// 給學生類添加 上課的方法
func ( s student ) goToSchool( ){
fmt.Println( p.name, " 在 ", p.school, " 上學" )
}
// s表示 student 簡寫
s1 := &student { school:"xxx科技大學" } // 注意go沒有構造函數, 這裏初始化的時候 尚未繼承person類,先初始化以後才繼承person類。才能使用繼承的屬性和方法
s1.id = 123
s1.name = "王奇疏"
s1.sex = 1
s1.eat( "一鯨(斤)米飯" )
s1.goToSchool()
輸出:
王奇疏 吃了 一鯨(斤)米飯
王奇疏 在 xxx科技大學 上學
4). go語言的接口 interface 契約編程, 是使用 隱式接口 的方式實現 接口。
當1個類 只要實現了某個接口的全部方法, 那麼這個類不用任何顯示聲明,即表示這個類已經實現了這個接口。 這種隱式實現接口,也致使了代碼不方便管理的一些問題/好比移動代碼以後 也許就出問題了。
// 定義1我的類接口
type Iperson interface {
func eat( food string )
func walk( )
func say( msg string )
func laugh( )
}
因爲上述 person類已經編寫了 這4個方法,因此person類就已經自動實現了 Iperson這個接口。
person類不須要像別的語言同樣顯式聲明 implement Iperson,就已經自動實現了該接口。
面向對象中 接口的用處:
接口做用是一份契約規範, 好比說車管所對全部牌子的 汽車都規定一樣的檢查次序步驟。
數據庫接口,對多種數據庫提供同樣相似的接口,方便統一規範開發。
日常接觸比較多的例子就是對多種數據庫的接口。 作遊戲 行業的,也會有感觸。
若是沒有接口作契約, 那車管所都不知道該怎麼檢測那麼多品牌的汽車、好比私自改裝的車是不能經過年檢的;
假設沒有契約規範, 在公司裏面、開發人員一多,問題也會出現。 是差很少的。
5). 設計模式。 (暫略)
6、引用和指針
(暫略)
參考書籍《go語言編程》( 許式偉 )
7、多平臺交叉編譯( windos、linux、arm安卓蘋果 、 mips路由器 )
(暫略)
gdb調試: 能夠用gdb對 go編譯的二進制文件進行調試,請參考gdb文檔。
8、常見錯誤
(暫略)