golang数组和切片作为参数和返回值的实现

目录
  • 1. 数组作为参数和返回值时
    • 1.1数组的定义
    • 1.2数组作为参数和返回值的时候
  • 2.切片作为参数和返回值
    • 2.1 切片的定义初始化
    • 2.2 切片的存储大致分为3部分
    • 2.3 切片作为参数和返回值
    • 2.4 append 切片动态增长的原理
    • 2.5 copy 函数 通过赋值切片可以使得两个切片的数据不共享
  • 3. 总结:

1. 数组作为参数和返回值时

1.1数组的定义

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型

var arr [10]int  //定义长度为10的类型是int的数组arr
arr[0] = 1   // 数组的下标从0开始 数组的赋值
var arr1 = [5]int{1,2,3,4,5}  //数组的初始化的定义方式
arr2 := [5]int{1,2,3,4,5} //同上
arr3 := [...]int{1,2,3,4,5} //编译器通过元素个数自动推断数组的长度

1.2数组作为参数和返回值的时候

func GetArray(arr [5]int)(v [5]int){
    fmt.Printf("GetArray arr===%v, %p\n", arr,&arr) // 查看传进来的参数和地址
    arr[1] = 3 //修改其中的一个值
    return arr
}

func main(){
    arr :=[...]int{1,2,3,4,5}  // 定义一个长度为5 类型是int的数组
    fmt.Printf("main arr=%v, %p\n", arr, &arr)
    value := GetArray(arr)
    fmt.Printf("main GetArray value=%v, %p, arr=%v,%p\n", value, &value,arr, &arr)
}

输出结果:
main arr=[1 2 3 4 5], 0xc000012390
GetArray arr===[1 2 3 4 5], 0xc000012420
main GetArray value=[1 3 3 4 5], 0xc0000123f0, arr=[1 2 3 4 5],0xc000012390

从上面的输出结果来看 当使用数组作为参数和返回值的时候,传进去的是值,在函数内部对数组进行修改并不会影响原数据

2.切片作为参数和返回值

2.1 切片的定义初始化

Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

var myslice []int  //定义一个切片 所有的数据类型都是int 切片与数组的定义差别是可以不带长度
var myslice []int = make([]int ,5) //定义一个长度为5的切片 
myslice1 := make([]int,5) //同上 
make([]T, length, capacity) //定义的参数分别是类型,长度,容量(可选)
myslice2 :=[] int {1,2,3 }   //切片初始化
myarr := [...]int{1,2,3,4,5} 
myslice3 := myarr[1:3] //也可以先定义一个数组 然后截取这里是从下标1开始到下标为3(不包含)

ps:当我们通过从数组截取获得切片的时候,我们可以发现截取后的切片和原来的数组是共用数据源的,如果修改原来的数组数据源 那么通过截取数组得到的切片的值也会被修改反之亦然

func main(){
    arr :=[...]int{1,2,3,4,5}  // 定义一个长度为5 类型是int的数组
    myslice1 := arr[0:3] //切片获取下标[0,3)的值
    myslice2 := arr[0:4] //切片获取下标[1,4)的值
    fmt.Printf("myslice1=%v, ppp=%p\n", myslice1, &myslice1)
    fmt.Printf("myslice2=%v, ppp=%p\n", myslice2, &myslice2)
    arr[1] = 666 //修改数组的值
    fmt.Printf("After myslice1=%v, ppp=%p\n", myslice1, &myslice1)
    fmt.Printf("After myslice2=%v, ppp=%p\n", myslice2, &myslice2)
    myslice2[2] =777 //修改切片的值
    fmt.Printf("arr=%v", arr)
}

输出的结果:
myslice1=[1 2 3], ppp=0xc000004078
myslice2=[1 2 3 4], ppp=0xc000004090
After myslice1=[1 666 3], ppp=0xc000004078
After myslice2=[1 666 3 4], ppp=0xc000004090
arr=[1 666 777 4 5]

2.2 切片的存储大致分为3部分

一部分是存的指向匿名数组的指针,一个是长度,一个是容量,我们在定义切片的时候 会在底层保存一个匿名的数组,通过上面的数组得到切片的方式得出的结论 当我们通过一个切片得到另一个切片的时候我们的数据源也是共享的

2.3 切片作为参数和返回值

func GetSlice(myslice []int)(value []int){
    fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看传进来的参数和地址
    myslice[2] = 10
    return myslice
}

func main(){
    var myslice []int //定义一个空的切片
    myslice = append(myslice, 1)
    myslice = append(myslice, 2)
    myslice = append(myslice, 3)
    myslice = append(myslice, 4)
    myslice = append(myslice, 5) //向切片里面追加元素
    fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice)
    rslice := GetSlice(myslice)
    fmt.Printf("rslice==%v ppp=%p, myslice==%v,ppp=%p\n", rslice,&rslice,myslice,&myslice)
}

输出结果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
GetSlice myslice===[1 2 3 4 5], ppppp=0xc0000040c0
rslice==[1 2 10 4 5] ppp=0xc0000040a8, myslice==[1 2 10 4 5],ppp=0xc000004078

结论:从上面的输出的结果和地址来看,当切片作为参数的时候穿进去的是值,也就是值传递,但是当我在函数里面修改切片的时候,我们发现源数据也会被修改,这是因为我们在切片的底层维护这一个匿名的数组,当我们把切片当成参数的时候,会重现创建一个切片,但是创建的这个切片和我们原来的数据是共享数据源的,所以在函数内被修改,源数据也会被修改

2.4 append 切片动态增长的原理

golang提供了append 函数向切片中增加元素,但是切片和数组一样也是有长度的,如果添加的元素个数刚好在长度范围内,就直接在末尾添加元素,但是如果添加的元素的个数超过了长度之后,就需要对底层的数组进行扩容了,这个新的数组的长度是原来的两倍 ,而创建这个新的数组之后我们将新的数组的指针保存到切片数据中,就这样我们实现了切片的动态增长,而当切片作为参数的时候,如果我们在函数里使用append函数增加元素,且元素的个数超过长度的话 在函数中我们就会创建除一个新的切片这个时候我们在函数内对新的切片进行修改 就不会影响到原来的切片了

func GetSlice(myslice []int)(value []int){
    fmt.Printf("GetSlice myslice===%v, ppppp=%p\n", myslice,&myslice) // 查看传进来的参数和地址
    myslice = append(myslice, 6)
    return myslice
}

func main(){
    myslice := make([]int,5)  //定义长度为5 类型是int的切片
    for i:=0; i< len(myslice);i++{
        myslice[i] = i+1
    }
    fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice)
    rslice := GetSlice(myslice)
    fmt.Printf("rslice==%v ppp=%p, myslice==%v,ppp=%p\n", rslice,&rslice,myslice,&myslice)
}

输出结果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
GetSlice myslice===[1 2 3 4 5], ppppp=0xc0000040c0
rslice==[1 2 3 4 5 6] ppp=0xc0000040a8, myslice==[1 2 3 4 5],ppp=0xc000004078

2.5 copy 函数 通过赋值切片可以使得两个切片的数据不共享

func main(){
    myslice := make([]int,5)  //定义长度为5 类型是int的切片
    for i:=0; i< len(myslice);i++{
        myslice[i] = i+1
    }
    fmt.Printf("myslice ==%v ppp=%p\n", myslice, &myslice)
    copymyslice := make([]int,5)
    copy(copymyslice, myslice)
    myslice[4] = 10
    fmt.Printf("copymyslice ==%v myslice=%v\n", copymyslice, myslice)
}

输出结果:
myslice ==[1 2 3 4 5] ppp=0xc000004078
copymyslice ==[1 2 3 4 5] myslice=[1 2 3 4 10]

结论:使用copy函数对切片进行赋值的时候可以避免源数据与目标数据共享底层数组

3. 总结:

数组还是切片,在函数中传递的时候如果没有指定为指针传递的话,都是值传递,但是切片在传递的过程中,有着共享底层数组的风险,所以如果在函数内部进行了更改的时候,会修改到源数据,所以我们需要根据不同的需求来处理,如果我们不希望源数据被修改话的我们可以使用copy函数复制切片后再传入,如果希望源数据被修改的话我们应该使用指针传递的方式

到此这篇关于golang数组和切片作为参数和返回值的实现的文章就介绍到这了,更多相关golang数组和切片作为参数和返回值内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈golang类型断言,失败类型断言返回值问题

    失败的类型断言,返回的值为最近断言类型的零值 代码入下: func main() { var data interface{} = "ehoo" if res, ok := data.(int); ok { fmt.Printf("int res:%d\n", res) } else if res, ok := data.(bool); ok { fmt.Printf("bool res:%b\n", res) } else { fmt.Prin

  • Golang的func参数及返回值操作

    参数及返回值 参数一指定数据类型为int 参数二 (-interface{}) 可传任何多个不同类型的参数 返回值:单个返回值直接指定数据类型可以不使用 (),多个返回值需使用().各返回值之间使用逗号分隔 func main() { demo.Params(10, 20, "golang", true) } func Params(id int, params ...interface{}) (error, error) { fmt.Println(id) fmt.Println(p

  • 通过汇编看golang函数的多返回值问题

    golang这门语言,有个比较好的特性,就是支持函数的多返回值.想C,C++,Java等这些语言,是不支持函数多返回的.但是C,C++可以使用传递指针,实现函数多返回.但是,你有没有想过,golang是怎样实现函数多返回值的呢? 我们知道,C,C++是通过寄存器实现函数返回值的,也就是先把返回值写入到一个寄存器中,然后再从寄存器中,读到函数的返回值.golang也是这样实现的吗? 伟大的思想家孔子曾说过,在源码面前一切都如同裸奔.后来,鲁迅先生,总结了孔子的思想,说出了,在汇编面前,一切语法都是

  • golang数组和切片作为参数和返回值的实现

    目录 1. 数组作为参数和返回值时 1.1数组的定义 1.2数组作为参数和返回值的时候 2.切片作为参数和返回值 2.1 切片的定义初始化 2.2 切片的存储大致分为3部分 2.3 切片作为参数和返回值 2.4 append 切片动态增长的原理 2.5 copy 函数 通过赋值切片可以使得两个切片的数据不共享 3. 总结: 1. 数组作为参数和返回值时 1.1数组的定义 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型.字符串或者自定义类型 var

  • C语言中数组作为函数的参数以及返回值的使用简单入门

    函数通过数组作为参数 如果想通过一个一维数组作为函数的参数,就必须声明函数形式参数,使用以下三种方式与所有三个声明方法之一产生类似的结果,因为每一种方式告诉编译器,一个整数指针将会要被接收.类似的方式,可以使用多维数组形式参数. 方式-1 形式参数为指针如下.在下一章将学习什么是指针. void myFunction(int *param) { . . . } 方式-2 如下形式数组参数的大小: void myFunction(int param[10]) { . . . } 方式-3 如下形式

  • Java如何实现http接口参数和返回值加密

    目录 参数和返回值得加密目的 具体实现方式 大致思路 代码实现 身份检验 参数和返回值得加密目的 为了保证接口不被人拦截下来恶意请求,保证程序的稳定性,我们可以使用接口加密的方法来保证参数和返回值的保密性. 具体实现方式 因为本人是写Java 的,所以这里就直接以Java代码为例.思想都是一样的,只是不同的语言都不同的实现方式. 大致思路 我们的参数和返回值只需要定义两个参数:ak,ct,ak存放堆成加密的秘钥,ct存放加密之后的请求内容. 加密方式用到AES对称加密和RSA非对称加密,将请求参

  • 存储过程的输出参数,返回值与结果集

    每个存储过程都有默认的返回值,默认值为0.下面我们分别看看在management studio中如何查看输出参数,返回值以及结果集,然后我们再在ASP.NET调用存储过程中如何获得输出参数,返回值以及结果集. 首先:在sql server management studio中查看输出参数,返回值以及结果集.本示例以Northwind数据库为例. 复制代码 代码如下: create proc Employee @Rowcount int=0 output as begin SELECT * FRO

  • Python 函数用法简单示例【定义、参数、返回值、函数嵌套】

    本文实例讲述了Python 函数用法.分享给大家供大家参考,具体如下: demo.py(函数定义): # say_hello() # 不能在定义函数之前调用函数 # Python 解释器知道下方定义了一个函数 def say_hello(): """函数的说明文档""" print("hello 1") print("hello 2") print("hello 3") print(&q

  • Python学习笔记之函数的参数和返回值的使用

    01.函数参数和返回值的作用 函数根据 有没有参数 以及 有没有返回值,可以相互结合,共有四种: 无参数 无返回值 无参数 有返回值 有参数 无返回值 有参数 有返回值 定义函数时候,是否接收参数,或者时候返回结果,是根据实际功能需求决定的. 如果函数内部处理的数据不确定,就可以将外界的数据以参数形式传递到函数内部. 如果希望一个函数执行完成后,向外界汇报执行结果,就可以增加函数的返回值. 02.函数的返回值-进阶 在程序开发中,有时候,会希望一个函数执行结束后,告诉调用者一个结果,以便调用者针

  • 对python3 中方法各种参数和返回值详解

    如下所示: # -*- coding:utf-8 -*- # Author: Evan Mi # 函数 def func1(): print('in the func1') return 0 # 过程 def func2(): print('in the func2') """ 多个值用逗号分割后返回,会分装到一个tuple中返回, 接收的时候,如果使用一个变量接收,那么这个接收变量就是一个tuple类型的 如果接收的时候也用逗号分割多个值来接收,那么可以分别对应返回tupl

  • C#调用Python程序传参数获得返回值

    目录 说明 1. Python 脚本 2. 打包成Windows可执行文件 3. C# 程序 4. 参考 说明 C# 调用 Python 程序有多种方式,本篇用的是第 4 种: nuget的ironPython: 用 c/c++ 调用python,再封装成库文件,c# 调用: c# 命令行调用.py文件执行: python 程序制作成 .exe 可执行文件,c# 使用命令行进行传参取返回值. 1. Python 脚本 先建个测试脚本 d://Test/EchoHi.py 代码如下: import

  • java中有无参数和返回值的方法详解

    目录 java有无参数和返回值 以下的例子要细细查看 方法的返回值和参数 1.返回值 2.参数 java有无参数和返回值 首先,定义一个土豪类(LocalTyrant) 属性:name moeney smoke 行为一:(无参数无返回值): 行为二:(无参数有返回值): 行为三:(有参数有返回值): 行为四:(有参数无返回值): 以下的例子要细细查看 慢慢分析,切不可急于求成 package cm.tr; class LocalTyrant{ String name; int money; St

随机推荐