golang函数使用基础

函数

介绍

有其他语言基础的话就没啥介绍的,基本语法:

func functionName(形参列表) (返回值列表){
    执行语句
    return 返回值列表
}
例子:
func getSum(n1 int, n2 int) int {
    var res int = n1 +n2
	return res
}

实际就创建不同的文件夹,存放程序文件。Go的每一个文件都输属于一个包的,go以包的形式来管理文件和目录结构。
作用:

  • 区分相同名字的函数与变量符
  • 当项目比较复杂时,便于管理项目
  • 控制函数、变量的访问范围,也就是作用域

打包指令:package 包名
引入指令:import "包路径"

注意事项:

  • 包中的函数与变量如果首字母大写则是对外公开的,称为该函数可以导出,如果小写则是非公开的
  • 包名通常应该与所处文件夹保持一致,不一致也可以
  • 同一个包下面,不能有相同的函数名
  • main包只能有一个

init函数

每一个源文件都可以包含一个init函数,该函数在main函数执行之前被Go运行框架调用。一般完成初始化工作 。

在一个文件中如果同时含有全局变了定义、init函数与main函数,那么执行流程是:
全局变量定义->init函数->main函数

当一个文件引用的包里面有全局变量定义与init函数时,先执行包的全局变量定义与init函数,再执行该文件的全局变量定义与init函数,最后执行main函数

匿名函数

如果希望某一个函数只使用一次,可以考虑匿名函数。当然匿名函数也可以实现多次使用。什么场景下会使用匿名函数呢?也就是闭包。一个最常用的场景就是程序运行出现错误的时候,我们要去恢复,一般是通过关键字defer,我们要有一个程序逻辑,在某些特定场景下运行的,但是我没有必要为整个逻辑定义函数,通常这样就可以使用闭包来做。

  • 使用方式1:在定义时就使用
res1 := func (n1 int, n2 int) int {
    return n1+n2
}(5, 6)//传入参数
fmt.Printf("res1的值是%d\n", res1)  //结果为11
  • 使用方式2:将匿名函数赋给一个变量,通过变量调用函数,可以反复调用(用处感觉不是很大,用处是可以在main()中定义函数)
func main(){
    a = func (n1 int, n2 int) int {  //此时a的数据类型为函数类型
        return n1+n2
    }
    res2 := a(5, 6)  //a是变量,不是函数名
    fmt.Printf("res2的值是%d\n", res2)  //结果为11
    res3 := a(10, 6)  //a是变量,不是函数名
    fmt.Printf("res3的值是%d\n", res3)  //结果为16
}
  • 使用方式3:全局匿名函数:将匿名函数赋给一个全局变量,通过变量调用函数

闭包

闭包是一个函数和与其相关的引用环境组成的整体。例子:

package main
import (
    "fmt"
)

func AddUpper() func (int) int {
    var n int = 10
    return func(x int) int {
        n = n + x;
        return n
    }
}

func main(){
    f := AddUpper()
    fmt.Println(f(1)) //结果为11
    fmt.Println(f(2)) //结果为13
    fmt.Println(f(3)) //结果为16
    g := AddUpper()
	fmt.Println(g(2)) //结果为12
}
// AddUpper是一个函数,其返回的数据类型是函数类型。
// 返回的匿名函数就是闭包的函数。
// n是引用的环境,构成了一个整体
// 可以理解为闭包是一个类,环境就是成员变量,匿名函数是唯一的一个成员函数。

defer

在函数中需要创建资源(redis,MySQL链接或者文件、锁资源),为了在函数执行完毕后及时的释放资源,Go的设计者提供了defer机制。

package main

import "fmt"

func sum(n1 int, n2 int) int {
    // 当执行到defer时,会将defer后面的语句压入到一个独立的栈中,暂时不执行
    // 当函数执行完毕后,再从栈中按照先入后出的方式出栈,并一一执行
    // 在defer将语句入栈时,也会将语句相关的资源与变量拷贝至栈中,在以下两个语句中分别就是n1, n2
    defer fmt.Println("ok1 n1=", n1)
    defer fmt.Println("ok2 n1=", n2)
    res := n1 + n2
    fmt.Println("ok3 res=", res)
    return res
}

func main(){
    res := sum(10, 20)、
    fmt.Println("res的值是", res)
}

以上代码的输出结果为:

ok3 res= 30
ok2 n1= 20
ok1 n1= 10
res的值是 30

函数参数的传递方式

  1. 值传递:基本的数据类型,int,float,string,数组,结构体,内存一般在栈上分配

  2. 引用传递:指针,切片,map,管道chan,interface,本质上是地址拷贝,地址拷贝效率更高。内存通常在堆上分配

func test(n1 *int, n2 *int) int{
    *n1 = *n2 + 5
    return *n1
}

变量作用域

  • 函数内部声明或者定义的变量叫局部变量,作用域仅限于函数内部
  • 函数外部声明或者定义的变量为全局变量,作用域在整个包都有效,如果首字母大写,这在整个程序都有效
  • 在if/for中声明的变量只在这个if/for代码块中有效
  • 就近原则:if/for > 函数内部 > 全局变量

常用的字符串函数

// 统计字符串的长度,不用调包,是内建函数
// 返回v中字节的数量,不是元素的数量,是字节的数量,一共汉字是三个字节
func len(v type) int

// 字符串遍历,同时处理有中文的问题
r := []rune(str) //将字符串转为了切片

// 字符串转整数,需要用包strconv, 如果失败会产生erorr
str1 :="12345"
n err := strconv.Atoi(str1)// n==13245
if err != nil{
    fmt.Println("转换错误:", err)
}else{
    fmt.Println("n的值是:", n)
}

// 整数转为字符串
str2 = strconv.Itoa(123)
fmt.Println("str的值是:", str2)

// 查找一个字符串是否含有某一个子串
strings.Contains(str1, str2)//返回值是bool类型
posted @ 2024-05-31 18:51  机械心  阅读(18)  评论(0编辑  收藏  举报