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语言函数编程的主要内容,如果未能解决你的问题,请参考以下文章