Golang -- 函数

前端之家收集整理的这篇文章主要介绍了Golang -- 函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

函数声明

@H_403_4@func (p myType ) funcName ( a,b int,c string ) ( r,s int ) {
    函数体
    @H_403_4@return 语句
}
  • func 关键字
  • (p myType) 表明 函数所属于的类型对象!,即为特定类型定义方法,可以省去不写,即为普通的函数 (这里我们主要讲解 普通的函数
  • 函数
  • 参数 (可以不声明)
  • 返回值 (可以不声明)
  • 函数

函数调用

我们知道C++的类中有 private,public,friend,可以控制类成员可见度。并且通过命名空间来减少命名冲突。Java也是如此。
在Go语言中 和python一样,也是采用 package 来对 不同的模块 进行划分的。

其中第2中和第4中都是来自外部包,并且函数名称第一个字母都是大写字母,所不同的是标准包有Go提供,而用户自己创建的包由用户自己创建。

@H_403_4@import "pcakageName"
packageName.FunctionName(参数)

第三种情况由于被掉函数 和 主调函数在同一个包中,所以直接调用即可,无需导入包名并且函数首字母可以是小写字母 (这里,哪怕两个两个函数不在同一个文件中,只要在同一个包中即可)。

调用标准函数

Golang 提供了 大量的包和实用函数用户使用,这些函数被称为标准函数。常见的标准包有 fmt,math,os,time bytes 一般包名都是小写。、
标准包的消息可以在 Go安装目录的 pkg 下面查看,也可以使用godoc 查看。

调用自定义函数

通常,一个可执行的Go程序一般都有一个 main 包,在 main包中必须声明一个 main 函数

调用 外部包的函数

如果需要调用外部包的函数,那么需要导入这个包,才能调用相关函数(首字母必须大写)。

比如构建 mymath包:
1. 首先建立 mymath.go 源文件:定义了四个函数 (这个源文件,必须在目录 $GOPAHT/src/mymath 下面)

@H_403_4@package mymath

@H_403_4@func Add(a,b int) int {
    @H_403_4@return (a + b)
}
@H_403_4@func Sub(a,b int) int {
    @H_403_4@return (a - b)
}
@H_403_4@func Mult(a,b int) int {
    @H_403_4@return (a * b)
}
@H_403_4@func Div(a,b int) int {
    @H_403_4@if b != 0 {
        @H_403_4@return float32(a) / float32(b)
    } @H_403_4@else {
        @H_403_4@return 0
    }
}
  1. 调用 go install mypath ,将会在$GOPAHT/src/mymath 下面 编译这些源文件,并且安装到 $GOPATH/src/pkg/(体系结构名)/下面

  2. 导入这个包之后就可以直接调用了这些函数了。 系统会在相应的下面找到这个 package,并且找到这些包中的函数。(go buildgo install的区别是什么?)

调用内置函数

13个内置函数,这些内置函数,非常有用。
len():可以获取数组,字符串,切片的长度
panic() 可以直接作用于系统底层,用于错误处理。


参数传递

参数传递主要是为了在函数之间,传递数据。
Go 语言中,函数参数可以使值类型,也可以是引用类型。值类型作为函数参数进行传递的时候是一个参数的拷贝。 引用类型是一个地址的拷贝。 大概分为以下几种类型:

常规传递

指针传递

数组元素 作为参数

数组名 作为参数 (将会进行数组的整体复制)

@H_403_4@package main 

@H_403_4@import (
    "fmt"
)

@H_403_4@func main() {
    @H_403_4@var b = [5]int {1, 2, 3, 4, 5}
    f4(b)
    fmt.Println(b[0])
}

@H_403_4@func f4(a [5]int) {
    a[0] += 1
    fmt.Println(a[0])  //不会影响原先的数组。因为传递数组名是指拷贝
}

在使用 数组名 作为参数的时候,实参类型和形参类型必须一致。 比如实参 b的类型是 [5]int,那么形参的类型也应该是 [5]int。 将形参定义为 []int,[10]int 等类型都是错误的,而C语言往往允许这么做。
Go 语言是类型安全的,[5]int 和 []int、[10]int 用演示不同的类型。 如果你的函数的返回值类型定义为 float32,那么如果你在函数中返回一个 int 类型变量也将不会通过。(Go语言是类型安全的)

Slice 作为函数参数

  1. 这是一个地址拷贝,将底层数组的地址赋值给参数的Slice
  2. 对Slice元素的操作即使对底层数组的操作。

函数作为参数传递

函数也是一种数据类型,可以将一个函数赋值给一个变量。

@H_403_4@func main(){
    @H_403_4@var a,b int = 3, 4
    f := sum
    f1(a,b,f)
}

@H_403_4@func f1(a,sum @H_403_4@func(int,int) int) int {
    fmt.Println(sum(a,b))
}

@H_403_4@func sum(a,b int) int {
    @H_403_4@return (a+b)
}

返回值

返回值: 允许多个返回值,并且允许定义返回值变量,这样return 语句可以更加方便。

@H_403_4@func f2(a,b int) (int,float32){  //多个返回值 需要一个括号
    @H_403_4@return a *b,float32(a) / float32(b)
}

同时在调用函数的时候,也可以忽略返回值。

@H_403_4@func main() {
    ret,_ := f2(3, 6)  //可以忽略返回值
}
@H_403_4@func f2(a,float32){
    @H_403_4@return a *b,float32(a) / float32(b)
}

可以命名返回值参数,这样在return 的时候,就可以不用直接写返回值了。

@H_403_4@func main() {
    sum,sub = f3(3, 6)
    fmt.Println(sum,sub)
}

@H_403_4@func f3(a,b int) (sum,sub int) { //直接命名了返回值参数,需要一个括号
    sum = a + b
    sub = a - b
    @H_403_4@return
}

变参函数

形式参数的 类型个数 都是可以变化的。
典型的变参函数有: fmt.Printf(),fmt.Scanf() exec.Command() 等

变参函数的声明

@H_403_4@func functionName (variableArgumetName ... dataType) returnValue {...}

(1) 变参的类型是”…类型“,而且变参必须是函数的最后一个参数。如果函数还有其他的参数,比如放在 变参的前面。 func f1(a int,s string,args ...int) {...}
(2) 不定长 的变参,实际上就是一个切片,可以使用 range 进行遍历。

@H_403_4@package main

@H_403_4@import "fmt"

@H_403_4@func main() {

    f1(1, 3)
    f1(4, 5, 6, 7)
}
@H_403_4@func f1(args ...int) {
    fmt.Println(args)
}
输出为:
[1 2 3]
[4 5 6 7]

变参函数的 传递

一个变参函数,如何将这些变参传递给另外一个 变参函数呢?
因为实际上变参就是一个切片,所以可以进行全部的传递,也可以进行部分的传递。

@H_403_4@package main

@H_403_4@import "fmt"

@H_403_4@func main() {

    f2(1, 3)
    f2(4, 7)
}
@H_403_4@func f1(args ...int) {
    fmt.Println(args)
}

@H_403_4@func f2(args ...int) {
    f1(args...)
    f1(args[2:]...)
}

不定长的变参在进行参数传递的是偶虽然接受到的是一个 Slice,但是和直接传递一个Slice还是有区别的:不定长参数在传递一个 Slice的时候,它仅仅是获取 Slice的一个副本对这个副本进行操作,不会改变原先的Slice的值。

任意类型的 变参函数

用户希望传递不同类型的参数的时候,就像 fmt.Printf() 可以接受 int string 等各种类型。
此时,应该指定 变参 类型为为 空接口 interface{}

@H_403_4@func f1(args... @H_403_4@interface{})  //指定变参类型为 interface{}

在Go语言中,interface{} 可以指向任何数据类型,所以可以使用 interface{}定义任意类型的变参。 同时 interface{] 也是类型安全的。 (对所有数据类型的抽象。。。吗?)

@H_403_4@package main

@H_403_4@import (
    "fmt"
)

@H_403_4@func main() {
    f1(2,"go", 8,"language",'a',false,"A", 3.24)
}
// 采用 interface {} 作为类型
@H_403_4@func f1(args ...@H_403_4@interface{}) {

    @H_403_4@var num = make([]int, 0, 6)
    @H_403_4@var str = make([]string, 6)
    @H_403_4@var ch = make([]int32, 6)   //字符类型,是int32的哦!
    @H_403_4@var other = make([]@H_403_4@interface{}, 6) //采用 interface{}作为类型

    @H_403_4@for _,arg := @H_403_4@range args {
        @H_403_4@switch v := arg.(@H_403_4@type) {  //这个是什么用法?
        @H_403_4@case int:
            num = append(num,v)
        @H_403_4@case string:
            str = append(str,v)
        @H_403_4@case int32:  //这里 'a' 被统计到了 int32中。
            ch = append(ch,v)
        @H_403_4@default:
            other = append(other,v)
        }
    }

    fmt.Println(num)
    fmt.Println(str)
    fmt.Println(ch)
    fmt.Println(other)
}
输出为:
[2 8]
[@H_403_4@go language A]
[97]
[false 3.24]

可以看到: Go 语言是类型安全的。 int 类型和 int32不是同一个类型,但是应该是兼容的。 字符 字面值 被当做rune类型(也就是 int32 类型,但是不是 int类型 )


匿名函数

声明:

@H_403_4@func (参数列表)(返回值){函数体}  //注意没有函数名,所以称为匿名函数
@H_403_4@func (a,b int) int {
    @H_403_4@return (a + b)
}
  1. 可以随时在代码里定义匿名函数,并且将这个匿名函数 赋值 给一个变量。
  2. 可以随时定义匿名函数,并且 执行这个 匿名函数。(声明函数的时候,直接执行!)
@H_403_4@package main

@H_403_4@import (
    "fmt"
)

@H_403_4@func main() {
    //声明 并且直接将 匿名函数 赋值 给变量f
    f := @H_403_4@func(a,b int) int {
        @H_403_4@return a + b
    }
    // 对函数类型的变量尽心调用
    sum := f(2, 3)  
    fmt.Println(sum)
    // 声明 并且 直接执行 匿名函数
    sum = @H_403_4@func(a,b int) int {
        @H_403_4@return a + b
    }(2, 3)
    fmt.Println(sum)
}

注意: 使用 匿名函数不能将它作为顶级函数使用,也就是说一定要将它放在其他函数函数体中。
2. 匿名函数中 可以 直接使用 上级函数中的变量(这也是其一个方便的用处)


函数闭包

closure:


defer 语句

  1. defer 语句 向函数进行注册
  2. 函数退出的时候执行(无论函数是 panic()还是正常退出
  3. defer 注册语句遵循 ”先注册后执行“的顺序
  4. 可以 用 defer 语句进行一些资源清理工作。

Golang 异常恢复机制

golang 的 异常恢复机制,是采用 panic() / recover() 的机制。 这些都是 内置函数

原文链接:https://www.f2er.com/go/190474.html

猜你在找的Go相关文章