go語言學習(二):函式、閉包、工程目錄
1.不定引數型別
func MyFun01(a int, b int){
//a = 111
fmt.Println(“a =”, a,b)
}
//…type不定引數型別
func MyFunc02(args …int){ //傳遞的實參可以是0個或者多個
//fmt.Println(“len(args) =”,len(args)) //獲取使用者傳遞引數的個數
for i:=0;i<len(args);i++{
fmt.Printf(“args[%d] = %d\n”, i, args[i])
}
fmt.Println("===================")
//range返回2個值,第一個是下標,第二個是下標對應的資料
for i,data := range args{
fmt.Printf(“args[%d] = %d\n”, i, data)
}
}
func main() {
MyFunc02()
fmt.Println("+++++++++++++++++")
MyFunc02(1)
fmt.Println("+++++++++++++++++")
MyFunc02(1,2,3)
}
2.不定引數的傳遞
func myfunc(tmp ...int){ for _,data := range tmp{ fmt.Println("data =", data) } } func myfunc2(tmp ...int){ for _,data := range tmp{ fmt.Println("data =", data) } } func test(args ...int){ //全部元素傳遞給myfunc //myfunc(args...) //只想把後2個引數傳遞給另外一個函式使用 //myfunc2(args[0:2]...) //從0到2(不包括2)傳遞過去 myfunc2(args[2:]...) //從args[2]開始(包括本身),把後面所有元素傳遞過去 } func main() { test(1, 2, 3) }
3.單返回值常用寫法
func myfunc01() int{
return 666
}
//給返回值起一個變數名,go推薦寫法
//常用寫法
func myfunc02() (result int) {
result = 666
return
}
func main() {
//無參返回值函式呼叫
var a int
a = myfunc01()
fmt.Println("a =", a)
//自動推導型別
b := myfunc02()
fmt.Println("b =", b)
}
4.多個返回值
//多個返回值 func myfunc01() (int, int, int){ return 1, 2, 3 } //go官方推薦寫法 func myfunc02() (a int, b int, c int){ a, b, c = 111, 222, 333 return } func myfunc03() (a, b, c int){ a, b, c = 111, 222, 333 return } func main() { //函式呼叫 a, b, c := myfunc03() fmt.Println(a, b, c) }
求最大最小值
//函式名小寫私有,大寫公有
func MaxandMin(a, b int) (max, min int){
if a>b{
max=a
min=b
}else {
max=b
min=a
}
return
}
func main() {
//函式呼叫
max, min := MaxandMin(10, 20)
fmt.Println(max, min)
}
5.遞迴(斐波那且數列,漢諾塔)
;i<=100;i++{
sum+=i
}
return
}
func test02(i int) int {
if i==1{
return 1
}
return i + test02(i-1)
}
func main() {
//test(3)
var sum int
sum = test02(100)
fmt.Println(sum)
}
函式多型,定義函式變數
func Add(a, b int) int {
return a+b
}
//函式也是一種資料型別,通過type給一個函式型別起名
//FuncType它是一個函式型別
type FuncType func(int, int) int //沒有函式名字,沒有{}
func main() {
var result int
result = Add(1,1)
fmt.Println(result)
//宣告一個函式型別的變數
var fTest FuncType
fTest = Add //是變數就可以賦值
result = fTest(10, 20)
fmt.Println(result)
}
回撥函式實現函式多型性
type FuncType func(int, int) int
//實現想法
func Add(a, b int) int {
return a+b
}
func minus(a, b int) int {
return a-b
}
//回撥函式,函式有一個引數是函式型別,這個函式就是回撥函式
//計算器,可進行四則運算
//多型,多種形態,呼叫同一個介面,不同的表現,可以實現不同的表現,加減乘除的
//現有想法,後面再實現功能
func Calc(a, b int, fTest FuncType) (result int){
fmt.Println("Calc")
//result = Add(a, b) //Add這個函式必須先定義後,才能呼叫
result = fTest(a, b) //這個函式還沒有實現
return
}
func main() {
a := Calc(1, 1, Add)
fmt.Println(a)
b := Calc(1, 1, minus)
fmt.Println(b)
}
4.閉包
所謂閉包就是一個函式"捕獲"了和它在同一作用域的其他常量和變數,這就意味著當閉包被呼叫的時候,不管程式在什麼地方呼叫,閉包都能使用這些常量或者變數。它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。
匿名函式基本語法
func main() {
a := 10
str := "mike"
//匿名函式,沒有函式名字
f1 := func() { //:=自動推導型別,常用
fmt.Println(a,str)
}
f1()
//給定一個函式型別起別名
type FuncType func() //函式沒有引數,每有返回值
//宣告變數
var f2 FuncType
f2 = f1
f2()
//定義匿名函式,同時呼叫
func() {
fmt.Printf("a =%d, str =%\n", a, str)
}() //後面的()代表給匿名函式傳參,呼叫此匿名函式
//帶引數的匿名函式
f3 := func(i, j int){
fmt.Println(i, j)
}
f3(1, 2)
//定義時同時呼叫
func(i, j int){
fmt.Println(i, j)
}(10,20)
//匿名函式,有參有返回值
x, y :=func(i, j int) (max, min int) {
if i>j{
max = i
min = j
} else {
max = j
min = i
}
return
}(10, 20)
fmt.Println(x,y)
}
在匿名函式內修改外部變數仍同步修改,閉包以引用方式捕獲外部變數
//閉包捕獲外部變數的特點
func main() {
a := 10
str := "mike"
func(){ //在匿名函式內修改外部變數仍同步修改
//閉包以引用方式捕獲外部變數
a = 666
str = "gogogo"
fmt.Println(a, str)
}()
fmt.Println(a, str)
}
變數的生命週期不是由閉包的作用域決定,它不關心這些捕獲了的變數和常量是否已經超出了作用域,所以只有閉包還在使用它,這些變數就還會存在。
func test01() int {
//函式被呼叫時,x才分配空間,才初始化為0
var x int
x++
return x*x //函式呼叫完畢,x自動釋放
}
//函式的返回值是一個匿名函式,返回一個型別
func test02() func() int{
var x int //沒有初始化,值為0
return func() int{
x++
return x*x
}
}
func main() {
//fmt.Println(test01())
//fmt.Println(test01())
//fmt.Println(test01())
//fmt.Println(test01())
//返回值為一個匿名函式,返回一個函式型別,通過f來呼叫返回的匿名函式
//變數的生命週期不是由閉包的作用域決定
f := test02()
fmt.Println(f()) //1
fmt.Println(f()) //4
fmt.Println(f()) //9
fmt.Println(f()) //16
}
獲取命令列引數
package main
import (
"fmt"
"os"
)
func main() {
//接收使用者傳遞的引數,是以字串方式傳遞
list := os.Args
n := len(list)
fmt.Println("n = ", n)
for i := 0; i < n;i++{
fmt.Printf("list[%d] = %s\n",i,list[i])
}
for i, data := range list {
fmt.Printf("list[%d] = %s\n",i,data)
}
}
全域性變數:定義在函式外部的變數是全域性變數
區域性變數:定義在{}裡面的變數就是區域性變數,只能在大括號內有效。執行到定義變數那句話,才開始分配空間,離開作用域自動釋放
不同作用域允許定義同名變數,遵循就近原則
5.工作區
go程式碼必須放在工作區中,工作區其實就是一個對英語特定工程的目錄
它包含三個子目錄:src目錄、pkg目錄和bin目錄
-
src目錄:用於以程式碼包的形式組織並儲存Go原始碼檔案(比如:.go、.c、.h)。分檔案程式設計(多個原始檔),必須放在src目錄。
1)如果有多個檔案或多個包,配置src同級目錄的絕對路徑。
2)如果要自動生成pkg、bin目錄。需要使用go install命令。除了要配置GOPATH環境變數,還要配置GOBIN環境變數 -
pkg目錄:用於存放經由gp install命令構建安裝後的程式碼包(包含go庫原始碼檔案)的".a"歸檔檔案
-
bin目錄:與pkg目錄類似,在通過go install命令完成安裝後,儲存由go命令原始碼生成的可執行檔案
分檔案程式設計:
同級目錄:
- 同一個目錄,包名必須一樣
- 同一個目錄,呼叫別的檔案的函式,直接呼叫即可,無需包名引用
不同級目錄:
- 不同目錄,包名不一樣
- 呼叫不同包裡面的函式,格式:包名.函式名()
- 呼叫別的包的函式,這個包函式名字如果是小寫,無法讓別人呼叫;要想別人能呼叫,必須首字母大寫
main函式和init函式執行流程:
先執行匯入包中的函式,再執行init(),最後執行main()。但有時使用者可能需要匯入一個包,但是不需要引用這個包的識別符號,在這種情況,可使用空白識別符號_來重新命名這個匯入:
import _ "fmt"