<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
// 函數定義:a,b是形參 func add(a int, b int) { a = a + b } var x, y int = 3, 6 add(x, y) // 函數呼叫:x,y是實參
func change(a, b *int) { *a = *a + *b *b = 888 } var x, y int = 3, 6 change(&x, &y)
slice、map、channel都是參照型別,它們作為函數引數時其實跟普通struct沒什麼區別,都是對struct內部的各個欄位做一次拷貝傳到函數內部
package main import "fmt" // slice作為引數,實際上是把slice的arrayPointer、len、cap拷貝了一份傳進來 func sliceChange(arr []int) { arr[0] = 1 // 實際是修改底層資料裡的首元素 arr = append(arr, 1) // arr的len和cap發生了變化,不會影響實參 } func main() { arr := []int{8} sliceChange(arr) fmt.Println(arr[0]) // 1,陣列元素髮生改變 fmt.Println(len(arr)) // 1,實際的長度沒有改變 }
關於函數返回值
// 返回變數c已經宣告好了,在函數中可以直接使用 func returnf(a, b int) (c int) { a = a + b c = a // 直接使用c return // 由於函數要求有返回值,即使給c賦過值了,也需要顯式寫return }
不定長引數實際上是slice型別
// other為不定長引數可傳遞任意多個引數,a是必須傳遞的引數 func args(a int, other ...int) int { sum := a // 直接當作slice來使用 for _, ele := range other { sum += ele } fmt.Printf("len %d cap %dn", len(other), cap(other)) return sum } args(1) args(1,2,3,4)
append函數接收的就是不定長引數
arr = append(arr, 1, 2, 3) arr = append(arr, 7) arr = append(arr) slice := append([]byte("hello "), "world"...) // ...自動把"world"轉成byte切片,等價於[]byte("world")... slice2 := append([]rune("hello "), []rune("world")...) // 需要顯式把"world"轉成rune切片
在很多場景下string都隱式的轉換成了byte切片,而非rune切片,比如"a中"[1]
獲取到的值為228而非"中"
最經典的斐波那契數列的遞迴求法
func fibonacci(n int) int { if n == 0 || n == 1 { return n // 凡是遞迴,一定要有終止條件,否則會進入無限迴圈 } return fibonacci(n-1) + fibonacci(n-2) // 遞迴呼叫自身 }
函數也是一種資料型別
func functionArg1(f func(a, b int) int, b int) int { // f引數是一種函數型別 a := 2 * b return f(a, b) } type foo func(a, b int) int // foo是一種函數型別 func functionArg2(f foo, b int) int { // type重新命名之後,引數型別看上去簡潔多了 a := 2 * b return f(a, b) } type User struct { Name string bye foo // bye的型別是foo,也就是是函數型別 hello func(name string) string // 使用匿名函數來宣告struct欄位的型別為函數型別 } ch := make(chan func(string) string, 10) // 使用匿名函數向管道中新增元素 ch <- func(name string) string { return "hello " + name }
閉包(Closure)是參照了自由變數的函數,自由變數將和函數一同存在,即使已經離開了創造它的環境,閉包複製的是原物件的指標
package main import "fmt" func sub() func() { i := 10 fmt.Printf("%pn", &i) b := func() { fmt.Printf("i addr %pn", &i) // 閉包複製的是原物件的指標 i-- // b函數內部參照了變數i fmt.Println(i) } return b // 返回了b函數,變數i和函數b將一起存在,即使已經離開函數sub() } // 外部參照函數引數區域性變數 func add(base int) func(int) int { return func(i int) int { fmt.Printf("base addr %pn", &base) base += i return base } } func main() { b := sub() b() b() fmt.Println() tmp1 := add(10) fmt.Println(tmp1(1), tmp1(2)) // 此時tmp1和tmp2不是一個實體了 tmp2 := add(100) fmt.Println(tmp2(1), tmp2(2)) }
func basic() { fmt.Println("A") defer fmt.Println(1) fmt.Println("B") // 如果同一個函數裡有多個defer,則後註冊的先執行 defer fmt.Println(2) fmt.Println("C") }
func deferExecTime() (i int) { i = 9 // defer後可以跟一個func defer func() { fmt.Printf("first i=%dn", i) // 列印5,而非9,充分理解「defer在函數返回前執行」的含義,不是在「return語句前執行defer」 }() defer func(i int) { fmt.Printf("second i=%dn", i) // 列印9 }(i) defer fmt.Printf("third i=%dn", i) // 列印9,defer後不是跟func,而直接跟一條執行語句,則相關變數在註冊defer時被拷貝或計算 return 5 }
go語言沒有try catch,它提倡直接返回error
func divide(a, b int) (int, error) { if b == 0 { return -1, errors.New("divide by zero") } return a / b, nil } // 函數呼叫方判斷error是否為nil,不為nil則表示發生了錯誤 if res, err := divide(3, 0); err != nil { fmt.Println(err.Error()) }
Go語言定義了error這個介面,自定義的error要實現Error()方法
// 自定義error type PathError struct { path string op string createTime string message string } // error介面要求實現Error() string方法 func (err PathError) Error() string { return err.createTime + ": " + err.op + " " + err.path + " " + err.message }
何時會發生panic:
panic會執行什麼:
func soo() { fmt.Println("enter soo") // 去掉這個defer試試,看看panic的流程,把這個defer放到soo函數末尾試試 defer func() { // recover必須在defer中才能生效 if err := recover(); err != nil { fmt.Printf("soo panic:%sn", err) } }() fmt.Println("regist recover") defer fmt.Println("hello") defer func() { n := 0 _ = 3 / n // 除0異常,發生panic,下一行的defer沒有註冊成功 defer fmt.Println("how are you") }() }
介面是一組行為規範的集合
// 定義介面,通常介面名以er結尾 type Transporter interface { // 介面裡面只定義方法,不定義變數 move(src string, dest string) (int, error) // 方法名 (參數列) 返回值列表 whistle(int) int // 參數列和返回值列表裡的變數名可以省略 }
只要結構體擁有介面裡宣告的所有方法,就稱該結構體“實現了介面”,一個struct可以同時實現多個介面
// 定義結構體時無需要顯式宣告它要實現什麼介面 type Car struct { price int } func (car Car) move(src string, dest string) (int, error) { return car.price, nil } func (car Car) whistle(n int) int { return n }
介面值有兩部分組成, 一個指向該介面的具體型別的指標和另外一個指向該具體型別真實資料的指標
car := Car{"寶馬", 100} var transporter Transporter transporter = car
func transport(src, dest string, transporter Transporter) error { _,err := transporter.move(src, dest) return err } var car Car // Car實現了Transporter介面 var ship Shiper // Shiper實現了Transporter介面 transport("北京", "天津", car) transport("北京", "天津", ship)
// 方法接收者是值 func (car Car) whistle(n int) int { } // 方法接收者用指標,則實現介面的是指標型別 func (ship *Shiper) whistle(n int) int { } car := Car{} ship := Shiper{} var transporter Transporter transporter = car transporter = &car // 值實現的方法,預設指標同樣也實現了 transporter = &ship // 但指標實現的方法,值是沒有實現的
type Transporter interface { whistle(int) int } type Steamer interface { Transporter // 介面嵌入,相當於Transporter介面定義的行為集合是Steamer的子集 displacement() int }
空介面型別用interface{}表示,注意有{}
var i interface{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->}
空介面沒有定義任何方法,因此任意型別都實現了空介面
var a int = 5 i = a
func square(x interface{<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->}){<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->} // 該函數可以接收任意資料型別
注意:slice的元素、map的key和value都可以是空介面型別,map中的key可以是任意能夠用==操作符比較的型別,不能是函數、map、切片,以及包含上述3中型別成員變數的的struct,map的value可以是任意型別
// 若斷言成功,則ok為true,v是具體的型別 if v, ok := i.(int); ok { fmt.Printf("i是int型別,其值為%dn", v) } else { fmt.Println("i不是int型別") }
當要判斷的型別比較多時,就需要寫很多if-else,更好的方法是使用switch i.(type),這也是標準的寫法
switch v := i.(type) { // 隱式地在每個case中宣告了一個變數v case int: // v已被轉為int型別 fmt.Printf("ele is int, value is %dn", v) // 在 Type Switch 語句的 case 子句中不能使用fallthrough case float64: // v已被轉為float64型別 fmt.Printf("ele is float64, value is %fn", v) case int8, int32, byte: // 如果case後面跟多種type,則v還是interface{}型別 fmt.Printf("ele is %T, value is %dn", v, v) }
電商推薦流程
為每一個步驟定義一個介面
type Recaller interface { Recall(n int) []*common.Product // 生成一批推薦候選集 } type Sorter interface { Sort([]*common.Product) []*common.Product // 傳入一批商品,返回排序之後的商品 } type Filter interface { Filter([]*common.Product) []*common.Product // 傳入一批商品,返回過濾之後的商品 } type Recommender struct { Recallers []recall.Recaller Sorter sort.Sorter Filters []filter.Filter }
使用純介面編寫推薦主流程
func (rec *Recommender) Rec() []*common.Product { RecallMap := make(map[int]*common.Product, 100) // 順序執行多路召回 for _, recaller := range rec.Recallers { products := recaller.Recall(10) // 統一設定每路最多召回10個商品 for _, product := range products { RecallMap[product.Id] = product // 把多路召回的結果放到map裡,按Id進行排重 } } // 把map轉成slice RecallSlice := make([]*common.Product, 0, len(RecallMap)) for _, product := range RecallMap { RecallSlice = append(RecallSlice, product) } SortedResult := rec.Sorter.Sort(RecallSlice) // 對召回的結果進行排序 // 順序執行多種過濾規則 FilteredResult := SortedResult for _, filter := range rec.Filters { FilteredResult = filter.Filter(FilteredResult) } return FilteredResult }
面向介面程式設計,在框架層面全是介面。具體的實現由不同的開發者去完成,每種實現單獨放到一個go檔案裡,大家的程式碼互不干擾。通過設定選擇採用哪種實現,也方便進行效果對比
到此這篇關於GoLang函數與面向介面程式設計全面分析講解的文章就介紹到這了,更多相關GoLang函數與面向介面內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45