刚入门的小白请教大佬们一个关于切片的问题

cyhkkha · 2018-09-05 11:48:31 · 1094 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-09-05 11:48:31 的主题,其中的信息可能已经有所发展或是发生改变。

楼主只是简单想测试一下切片的删除头删除中间的部分,所以写了一个小demo测试一下,但是运行结果却很让我出乎意料


先贴上代码:

package main
import "fmt"
func main() {
    fmt.Println("测试:")
    var st []int
    for i:=0;i<12;i++{
        st=append(st,i)
    }
    fmt.Println("原切片:")
    fmt.Println(st)

    fmt.Println("删除切片指定头:")
    test1(st,2)
    fmt.Println(st)

    fmt.Println("删除切片指定位置:")
    test2(st,5)
    fmt.Println(st)
}

// 去除切片头,测试切片是否为引用传递?
func test1(s []int,i int){
    s = s[i:]
}

//去除中间
func test2(s []int,i int)  {
    // 和js6类似s[]...表示将数组转化为一列参数输入
    s = append(s[:i],s[i+2:]...)
}

以下是运行结果

测试:
原切片:
[0 1 2 3 4 5 6 7 8 9 10 11]
删除切片指定头:
[0 1 2 3 4 5 6 7 8 9 10 11]
删除切片指定位置:
[0 1 2 3 4 7 8 9 10 11 10 11]

Process finished with exit code 0

可以看到删除头的操作并没有成功

楼主一开始的理解是,go语言所有参数传递默认是值传递,所以传递过去的切片只是一个副本,在函数内部改变切片值是不起作用的

但是下面这个函数的运行s = append(s[:i],s[i+2:]...)就诡异了

原数组[0 1 2 3 4 5 6 7 8 9 10 11],输入值为2,运行结果是下面这个:

[0 1 2 3 4 7 8 9 10 11 10 11]

切片中间的5,6的确是删除了,可以看到切片的确是以引用的形式传到了函数内部,但后面的两位出现了重复,这是什么鬼?

百般思索下,觉得是在函数里不能对原切片的cap和len进行修改,只能作值的修改?切片映射的原数组会自动填补上缺失的部分?但是第一个函数也删去了切片的头值,但切片根本就没变啊?

求大佬们解决一下萌新的疑惑QAQ


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1094 次点击  
加入收藏 微博
10 回复  |  直到 2018-09-05 20:02:35
guanyibing
guanyibing · #1 · 7年之前

你打印的还是st,并不是操作后的切片,你应该用指针或者函数定义时返回结果切片

cyhkkha
cyhkkha · #2 · 7年之前
guanyibingguanyibing #1 回复

你打印的还是st,并不是操作后的切片,你应该用指针或者函数定义时返回结果切片

默默问一句,如果我不想写返回值的话,能否在test函数内部直接操作main里切片st,并反映到main?如果可以的话怎么实现呢?

jarlyyn
jarlyyn · #3 · 7年之前

golang里没有删除这个操作。

append到底是做什么的你也需要了解一下。

dingzewe
dingzewe · #4 · 7年之前
cyhkkhacyhkkha #2 回复

#1楼 @guanyibing 默默问一句,如果我不想写返回值的话,能否在test函数内部直接操作main里切片st,并反映到main?如果可以的话怎么实现呢?

函数直接用切片参数不行,你要想达到效果,参数要是a *[]int才行 package main

import "fmt"

func test(s []int) { s = (*s)[1:] }

func main() { s := []int{1,2,3,4,5} fmt.Println(s) test(&s) fmt.Println(s) }

cyhkkha
cyhkkha · #5 · 7年之前
dingzewedingzewe #4 回复

#2楼 @cyhkkha 函数直接用切片参数不行,你要想达到效果,参数要是a *[]int才行 package main import "fmt" func test(s *[]int) { *s = (*s)[1:] } func main() { s := []int{1,2,3,4,5} fmt.Println(s) test(&s) fmt.Println(s) }

谢谢,果然用指针就能成功

cyhkkha
cyhkkha · #6 · 7年之前
jarlyynjarlyyn #3 回复

golang里没有删除这个操作。 append到底是做什么的你也需要了解一下。

append我看官方注释是给切片追加数的功能:The append built-in function appends elements to the end of a slice

函数里用指针确实我的功能就能跑通了,感觉go不能老用面向对象的思想,以后还是写成返回值的形式吧

只是有点好奇为啥不用指针的时候,在函数里append切片,main里面的原来切片会受到影响,估计是append函数的问题

可惜看不到append函数的实现方式

jarlyyn
jarlyyn · #7 · 7年之前
cyhkkhacyhkkha #6 回复

#3楼 @jarlyyn append我看官方注释是给切片追加数的功能:`The append built-in function appends elements to the end of a slice` 函数里用指针确实我的功能就能跑通了,感觉go不能老用面向对象的思想,以后还是写成返回值的形式吧 只是有点好奇为啥不用指针的时候,在函数里append切片,main里面的原来切片会受到影响,估计是append函数的问题 可惜看不到append函数的实现方式

append的名字起得是个坑。

其实是这样的,组合两个数组。

如果第一个数组空间够,返回第一个数组。 如果第一个数组空间不够,返回一个新的足够大的数组……

cyhkkha
cyhkkha · #8 · 7年之前
jarlyynjarlyyn #7 回复

#6楼 @cyhkkha append的名字起得是个坑。 其实是这样的,组合两个数组。 如果第一个数组空间够,返回第一个数组。 如果第一个数组空间不够,返回一个新的足够大的数组……

原来如此,感情是test函数里切片覆盖了原数组的一部分,这样就解释的通了,的确是挺坑的

感谢大佬

guanyibing
guanyibing · #9 · 7年之前
cyhkkhacyhkkha #6 回复

#3楼 @jarlyyn append我看官方注释是给切片追加数的功能:`The append built-in function appends elements to the end of a slice` 函数里用指针确实我的功能就能跑通了,感觉go不能老用面向对象的思想,以后还是写成返回值的形式吧 只是有点好奇为啥不用指针的时候,在函数里append切片,main里面的原来切片会受到影响,估计是append函数的问题 可惜看不到append函数的实现方式

append只对切片有效,你可以试试s[:i]=append(s[i+2:]) return s[:I]

guanyibing
guanyibing · #10 · 7年之前
guanyibingguanyibing #9 回复

#6楼 @cyhkkha append只对切片有效,你可以试试s[:i]=append(s[i+2:]) return s[:I]

append只对切片有效,你可以试试s[:i]=append(s[:I],s[i+2:]) return s[:I]

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传