go语言函数编程

Posted 开源你我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言函数编程相关的知识,希望对你有一定的参考价值。

1.什么函数 

函数是构成代码执行逻辑结构,在go语言,函数基本组成: 关键字func、函数名、函数列表、返回值,函数体和返回语句。


2.定义一个函数

package addmath
import (
"errors"
)
func Add(a, b, c int) (ret int, err error){
if a < 0 || b < 0 {
err = errors.New("不能有负数存在")
return
  }
return a + b + c, nil
}

3.函数的调用


先导包,然后按包名找到函数进行

import "addmath"

addmath.Add(10, 20, 30)


函数的函数名首字母的大小写体现函数的可见性,很重要记住这样一个规则:小写字母开头的函数只在本包内可见,大写字母开头函数才能被其他包调用。


案例完整代码:

        package handle

     import (

     "errors"

     "fmt"

     )


func Add(a, b, c int) (ret int, err error){

if a < 0 || b < 0 {

err = errors.New("不能有负数存在")

return 1, err

}

ArrayBianli()

return a + b + c, err


}


func ArrayBianli() {

arr :=[10]int{1, 3, 5, 6, 7, 9}

for i := 0; i < 10; i++ {

fmt.Print(arr[i], ", " )

}

fmt.Println("")

}


package  main

import (

"fmt"

"main/pkg/handle"

)

func main()  {

a, _ := handle.Add(10, 20, 30)

fmt.Println(a)

fmt.Println("main 遍历数组")

handle.ArrayBianli()

}


4.不定参数

4.1 不定参数入门   fmt.Println(), fmt.Printf()


一般情况一个函数的传入参数都是固定的,但是有一些函数能传入不定数量的参数(可变长的)。比如c语言中的printf。可以看:《C语言“…”占位符及可变参数函数》在Go语言中,也有这样的函数。用法类似,也是三个点。


func Myfunc(args ...int) {

for _, arg := range args {

fmt.Println(args)

}

}


4.2.不定参数传递

Myfunc2(args ...int) {

//函数体

}


func Myfunc(args ...int) {

//按原样传递

Myfunc2(args)

//传递片段,实际上任意int slice都可以传进去

Myfunc2(args[1:] ...)  //数组切片  args[start:end]  左闭右开

}


复习数组切片

arr := [10]int{1, 3, 5, 6, 8, 90, 10, 12, 13, 0}

slice1 := arr[0:] //1, 3, 5, 6, 8, 90, 10, 12, 13, 0

slice2 := arr[:2] //1, 3

slice3 :=  arr[3:8] //6, 8, 90, 10, 12

package  main


import "fmt"


func  Myfunc(args ...int) {  //[]int   //数组切片 ...int 语法 ...type

for _, args := range args {

fmt.Println(args)

}

}

func Myfunc2(args ...int) {

Myfunc(args...) //传递全部

//Myfunc(args[:2]...) //传递任意片段

}


func main()  {

Myfunc2(12, 13, 43, 12)

}


4.3.任意类型不定参数

之前的例子咱将type约定成int,现在咱想传递任意类型,在go语言里面,有这样一个关键字可以实现你的想法:interface


func Printf(format string, args ...interface{}) {

//...

}


案例:


package  main


import "fmt"


func MyPrintf(args ...interface{}) {

for _, arg := range args {

switch arg.(type) {

case int :

fmt.Println(arg, "This is int value")

case string:

fmt.Println(arg, "This is string value")

case int64:

fmt.Println(arg, "This is int64 value")

default:

fmt.Println(arg, "Unkown type")

}

}

}


func main() {

var v1 int  = 1

var v2 int64 = 12

MyPrintf(v1)

MyPrintf(v2)

}


5.函数多返回值


func Add(a, b int) (k string, v int )

{

return "加法", a+b

}


a, b := Add (1, 3)


package  main


import "fmt"


func Add(a, b, c int64) (k string, v int64) {

return "加法", a + b +c

}


func main() {

_, b := Add(1, 2, 4) //_是跳过返回值

//fmt.Println(a)

fmt.Println(b)

}


6.匿名函数


匿名函数是由一个不带函数名的函数声明和函数体组成


func (a, b, c int, z float64) bool {

return a*b+c < int(z)

}


匿名函数可以直接赋值给一个变量或者直接执行


v := func (x, y int) int {

return x + y // 直接赋值给一个变量

}


func(ch chan int){

ch <- ACK

}(reply_chan)


package  main


import "fmt"


func main() {

v := func (x, y int) int {

return x + y

}(10, 30)

fmt.Println(v)

}


7.闭包函数


func main (){

var j int  = 5

a := func()(func()) {

var i int = 10

return func() {

fmt.Printf("i, j: %d, %d\n", i,  j)

}

}()

a()

j *= 2

a()

}


8.错误处理


C- errno

java/C++ try ...catch ... finaly


8.1.error接口


type error interface {

Error() string

}


在go语言中,很多函数都可以定义为以下模式


func Foo(param int)(n int, err error){

//...

}


n, err := Foo()

if err != nil {

//错误处理

}else {

//使用函数返回值

}


//go语言库中的实际代码来示范如和使用自定义类型Error


type PathError struct {

Op string

Path string 

Err error

}


func (this *PathError) Error() string {

return this.Op + " " + this.Path + ":" + this.Err.error()

}


func  Stat(name string ) (fi FileInfo, err error){

var stat syscall.Stat_t

err := syscall.Stat(name, &stat)

if err != nil {

return nil, &PathError("stat", name, err)

}

return fileInfofoFromStat(&stat, name), nil

}


8.2.defer关键字


class file_closer 

{

FILE _f;

public:

file_closer(FILE f):_f(f){}

~file_close(){

if (f)

{

close(f);

}

}

};


file //fopen() open 用完了这个文件 fclose() close()


int main()

{

FILE f = fopen("a.txt")

//很多操作

。。。。。。。

......

//fclose(f)

}


file, err := os.Create(filename)

if(err != nil) {}

defer file.Close()

//在这儿做很多操作

。。

。。

。。。


defer执行顺序


package  main


import "fmt"


func defer_call(){

defer func() { fmt.Println("one")}()

defer func() {fmt.Println("two")}()

defer func() {fmt.Println("three")}()

panic("exception....")

}


func main() {

defer_call()

}


9.panic和recover


panic 意思是抛出一个异常, 和python的raise用法类似;recover是捕获异常,和python的except用法类似;defer会延迟函数到其他函数之后完之后再执行,后面跟的是函数。golang 的错误处理流程:当一个函数在执行过程中出现了异常或遇到panic(),正常语句就会立即终止,然后执行 defer 语句,再报告异

常信息,最后退出 goroutine。如果在 defer 中使用了 recover() 函数,则会捕获错误信息,使该错误信息终止报告。

package main

import (
"fmt"
)

func main() {
f()
fmt.Println("Returned normally from f.")
}

func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g()
fmt.Println("Returned normally from g.")
}

func g() {
panic("ERROR")
}

10.Go递归函数


Go支持递归函数。 下面是一个经典的阶乘例子


这个fact()函数实际上是调用它自己本身,直到它达到fact(0)时结果退出。closures.go的完整代码如下所示:

package main

import "fmt"

func fact(n int) int {
if n == 0 {
return 1
  }
return n * fact(n-1)
}

func main() {
fmt.Println(fact(7))
}

11.go语言函数完整示例

package main

import (
"algorithm/bubblesort"
  "algorithm/qsort"
  "bufio"
  "flag"
  "fmt"
  "io"
  "os"
  "strconv"
  "time"
)

var infile *string = flag.String("i", "unsorted.dat", "File contains values for sorting")
var outfile *string = flag.String("o", "sorted.dat", "File to receive sorted values")
var algorithm *string = flag.String("a", "qsort", "Sort algorithm")

func readValues(infile string) (values []int, err error) {
file, err := os.Open(infile)
if err != nil {
fmt.Println("Failed to open the input file ", infile)
return
  }
defer file.Close()

br := bufio.NewReader(file)

values = make([]int, 0)

for {
line, isPrefix, err1 := br.ReadLine()

if err1 != nil {
if err1 != io.EOF {
err = err1
}
break
     }

if isPrefix {
fmt.Println("A too long line, seems unexpected.")
return
     }

str := string(line)
fmt.Print(str, " ")
value, err1 := strconv.Atoi(str)

if err1 != nil {
err = err1
return
     }

values = append(values, value)
}
return
}

func writeValues(values []int, outfile string) error {
file, err := os.Create(outfile)
if err != nil {
fmt.Println("Failed to create the output file ", outfile)
return err
}
defer file.Close()
for _, value := range values {
str := strconv.Itoa(value)
file.WriteString(str + "\n")
}
return nil
}

func main() {
flag.Parse()

if infile != nil {
fmt.Println("infile =", *infile, "outfile =", *outfile, "algorithm =", *algorithm)
}

values, err := readValues(*infile)
if err != nil {
fmt.Println(err)
} else {
t1 := time.Now()
switch *algorithm {
case "qsort":
qsort.QuickSort(values)
case "bubblesort":
bubblesort.BubbleSort(values)
default:
fmt.Println("Sorting algorithm", *algorithm, "is either unknown or unsupported.")
}
t2 := time.Now()
fmt.Println("The sorting process costs", t2.Sub(t1), "to complete.")

writeValues(values, *outfile)
}
}
package bubblesort

func BubbleSort(values []int) {
for i := 0; i < len(values)-1; i++ {
for j := 0; j < len(values)-i-1; j++ {
if values[j] > values[j+1] {
values[j], values[j+1] = values[j+1], values[j]
}
}
}
}
package qsort

func quickSort(values []int, left, right int) {
temp := values[left]
p := left
i, j := left, right

for i <= j {
for j >= p && values[j] >= temp {
j--
}
if j >= p {
values[p] = values[j]
p = j
}
if values[i] <= temp && i <= p {
i++
}

if i <= p {
values[p] = values[i]
p = i
}
}

values[p] = temp //provKey  
  if p-left > 1 {
quickSort(values, left, p-1)
}
if right-p > 1 {
quickSort(values, p+1, right)
}
}

func QuickSort(values []int) {
quickSort(values, 0, len(values)-1)
}


以上是关于go语言函数编程的主要内容,如果未能解决你的问题,请参考以下文章

Go 语言网络编程系列— Socket 编程入门:Dial 函数及其使用

编程实践用 go 语言实现Bloom filter算法

Go语言学习-函数

浅谈Go语言 - 函数与结构体

Go语言入门

Go语言2