首页 > 其他分享 >【Go函数详解】二、参数传递、变长参数与多返回值

【Go函数详解】二、参数传递、变长参数与多返回值

时间:2024-08-27 10:24:49浏览次数:15  
标签:函数 int fmt 参数传递 add 参数 Go 返回值

文章目录


一、传递参数

1. 按值传参

Go语言默认使用按值传参来传递参数,即传递参数值的一个副本:
函数接收到传递进来的参数后,会将参数值拷贝给声明该参数的变量(形式参数,简称形参),如果在函数体中有对参数值做修改,实际上修改的是形参值,这不会影响到实际传递进来的参数值(简称实参)。

func add(a, b int) int  {
    a *= 2
    b *= 3
    return a + b
}

func main()  {
    x, y := 1, 2
    z := add(x, y)
    fmt.Printf("add(%d, %d) = %d\n", x, y, z)   //add(1, 2) = 8
}

x、y把值传递给a、b,主要原因是x、y的内存地址与a、b的内存地址并不相同,可以看作是两个值相等的不同变量,所以修改a、b的值并不会改变x、y的值。

2. 引用传参

如果想要实现在函数中修改形参值可以同时实参值,需要通过引用传参来完成,此时传递给函数的参数是指一个指针,而指针代表的是实参的内存地址,修改指针引用的值即修改内存地址中存储的值,所以实参的值也会被修改。

! 注意:这种情况下,传递的变量是地址值的拷贝,所以从本质上讲还是按值传递。

func add(a, b *int) int {
    *a *= 2
    *b *= 3
    return *a + *b
}

func main()  {
    x, y := 1, 2
    z := add(&x, &y)
    fmt.Printf("add(%d, %d) = %d\n", x, y, z)
}

在函数调用时,像切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型默认使用引用传参。

2.1 特殊情况

以下具体分析详见:(留个坑)

2.1.1 切片slice

把slice作为函数参数传递,若在函数内slice发生扩容的话,会让函数内外原本指向同一个底层数组的两个slice变量,分别指向两个不同的底层数组

2.1.2 字典map

把map作为函数参数传递,若在函数内map发生扩容的话,函数内外的map变量指向的底层内存仍是一致的。

二、变长参数

所谓变长参数指的是函数参数的数量不确定,即可以传递任意数量的参数到指定函数。合适地使用变长参数,可以让代码更简洁,尤其是输入输出类函数,fmt.Println的参数就是典型的变长参数。

1. 基本定义和传值

1.1 基本定义

在参数类型前加上...前缀,就可以将该参数声明为变长参数

func myfunc(numbers ...int) {
    for _, number := range numbers {
        fmt.Println(number)
    }
}

1.2 传值

1.2.1 普通传值
myfunc(1, 2, 3, 4, 5) 

函数 myfunc() 接受任意数量的参数,这些参数的类型全部是 int

1.2.2 传递切片

传递切片时需要末尾加上...作为标识,表示对应的参数类型是变长参数:

slice := []int{1, 2, 3, 4, 5}
myfunc(slice...)
myfunc(slice[1:3]...)

注:形如...type格式的类型只能作为函数的参数类型存在,并且是函数的最后一个参数

之所以支持传入切片,是因为从底层实现原理上看,类型...type本质上是一个切片,也就是[]type,这也是为什么上面的numbers可以用for循环来获取每个传入的参数值。

2. 任意类型的变长参数(泛型)

即指定变长参数类型为interface{}

func myPrintf(args ...interface{}) {
    for _, arg := range args {
        switch reflect.TypeOf(arg).Kind() {
        case reflect.Int:
            fmt.Println(arg, "is an int value.")
        case reflect.String:
            fmt.Printf("\"%s\" is a string value.\n", arg)
        case reflect.Array:
            fmt.Println(arg, "is an array type.")
        default:
            fmt.Println(arg, "is an unknown type.")
        }
    }
}

func main() {
    myPrintf(1, "1", [1]int{1}, true)
}

在这里插入图片描述
这里实现的是泛型功能,Go语言并没有在语法层面提供对泛型的支持,目前只能自己通过反射和interface{}类型实现。
interface{}是一个空接口,可以用于表示任意类型。但这个范围过于宽泛,像C语言中的void一样,我们根本不知道真正传递进来的参数到底是什么类型的,这在强类型的静态语言中是不能接受的,为了保证代码类型安全,需要在运行时通过反射对数据类型进行检查,以便让程序在预设的轨道内运行,避免因为类型问题导致程序崩溃。

三、多返回值

Go语言与其他编程语言一大不同之处在于支持多返回值,这才处理程序出错的时候非常有用。

func add(a, b *int) (int, error) {
    if (*a == 0 || *b == 0) {
        err := errors.New("只支持非负整数相加")
        return 0, err
    }
    *a *= 2
    *b *= 3
    return *a + *b, nil
}

func main()  {
    x, y := -1, 2
    z, err := add(x, y)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Printf("add(%d, %d) = %d\n", x, y, z)
}

如上,通过error指定多返回一个表示错误信息的、类型为error的返回值,函数的多个返回值之间可以通过逗号分隔,并且在最外面通过圆括号包起来。

1. 命名返回值

在设置多返回值时,可以对返回值进行变量命名,这样可以在函数中直接对返回值进行赋值,而不必每次都按照指定的返回值格式返回多个变量了。

func add(a, b *int) (c int, err error) {
    if (*a == 0 || *b == 0) {
        err = errors.New("只支持非负整数相加")
        return
    }
    *a *= 2
    *b *= 3
    c = *a + *b
    return
}

这种机制避免了每次进行 return 操作时都要关注函数需要返回哪些返回值,为开发者节省了精力,尤其是在复杂的函数中。

标签:函数,int,fmt,参数传递,add,参数,Go,返回值
From: https://blog.csdn.net/peaceLT/article/details/141560107

相关文章

  • Google Earth Engine(GEE)——GEE函数编写详解4000字(初学者看过来)
    简介代码编辑器提供了对地球引擎全部功能的访问;但是需要对编码和JavaScript的基础知识有基本的了解。在本练习中,您将继续学习JavaScript语法和一些新的EarthEngine空间数据概念。在本练习中,您将重点关注与EarthEngine中图像集合相关的基本概念和方法。这是让用户编......
  • 基于django+vue摊位管理系统分析与设计【开题报告+程序+论文】计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着城市化进程的加速与商业活动的日益繁荣,各类市场、集市及展会中的摊位管理成为了一个复杂而关键的问题。传统的手工记录与管理方式已难......
  • 高性能 Go 服务开发
            当我们搭建了一个完整的Go项目后,这个项目的性能如何呢?能否应对高并发流量(比如秒杀活动)呢?如果不能,我们该如何优化系统性能呢?性能优化的前提是确定服务瓶颈。1.分库分表        数据库通常是Web服务的性能瓶颈,为什么呢?因为一般情况下,单个数据库实......
  • AlphaGo Zero论文《Mastering the game of Go without human knowledge》阅读笔记
    AlphaGoZero论文阅读笔记原论文:《MasteringthegameofGowithouthumanknowledge》简述:论文提出了一种新的围棋人工智能算法AlphaGoZero,该算法可以在完全无监督的情况下进行训练,并且超越了之前的AlphaGoFan和AlphaGoLee的表现。该算法具有如下特点:在无监督的情况......
  • 网站提示410 Gone:请求的资源已不再可用怎么办
    当遇到“410Gone”错误时,这意味着客户端请求的资源在服务器上已经永久性地不可用。这通常意味着资源已被删除或移动到了一个新的位置,而服务器不希望客户端将来再尝试访问该资源。解决方案检查URL确认请求的URL是否正确。如果URL已经改变,需要更新客户端的链接指向新的......
  • Django缓存设置
    在Django中设置缓存可以显著提高网站的性能,特别是在处理大量请求或数据库查询时。Django支持多种缓存后端,包括内存缓存、文件缓存、数据库缓存和更高级的选项如Memcached和Redis。以下是如何在Django项目中设置缓存的基本步骤:1.选择缓存后端首先,你需要决定使用哪种缓存后端......
  • 网站提示506 Variant Also Negotiates:服务器内部配置错误怎么办
    当遇到“506VariantAlsoNegotiates”错误时,这意味着服务器存在内部配置错误,特别是与内容协商相关的配置问题。此错误通常与透明内容协商协议(TransparentContentNegotiationProtocol)有关,该协议定义在RFC2295中。解决方案检查服务器配置如果你是服务器管理员,检查服务......
  • golang 标准库(os)
    os标准库实现了平台(操作系统)无关的编程接口。1.创建文件packagemainimport( "fmt" "os")//创建文件funcCreatFile(FileNamestring){ f,err:=os.Create(FileName) iferr!=nil{ fmt.Println("err:",err) }else{ fmt.Printf("创建文件%v成......
  • 计算机毕业设计django+vue爱购电商平台【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和电子商务的日益普及,电商平台已成为人们购物的主要渠道之一。传统商业模式正逐步向线上转型,以适应消费者日益增......
  • 计算机毕业设计django+vue哈尔滨学院新生入学系统【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的普及与高校规模的不断扩大,新生入学工作变得日益复杂且重要。哈尔滨学院作为一所综合性高校,每年需迎接大量新生入学,传统的纸......