首页 > 其他分享 >go切片和指针切片

go切片和指针切片

时间:2024-04-13 22:44:51浏览次数:18  
标签:指针 切片 Person peopleSlice go peoplePtrSlice 结构

转载请注明出处:

  在Go语言中,切片(Slice)和指针的切片(即切片中每个元素都是指向某种数据类型的指针)是两个不同的概念,它们各自具有特定的用途和优势。

切片(Slice)

  切片是对数组的一个连续片段的引用,它提供了对数组元素集合的抽象表示。切片底层数据结构都是数组,它包含三个关键部分:指向数组起始元素的指针、切片长度和切片容量。切片长度是指切片当前包含的元素个数,而切片容量是指从切片的起始元素到底层数组的最后一个元素的个数。

  切片的一个重要特性是它提供了对底层数组的动态视图。这意味着你可以通过切片来访问、修改和操作数组的一部分或全部元素,而无需复制整个数组。此外,切片还可以方便地进行扩容和缩容操作,以满足不同场景下的需求。

  示例

package main  
  
import "fmt"  
  
func main() {  
    // 定义一个数组  
    array := [5]int{1, 2, 3, 4, 5}  
  
    // 创建一个切片,引用数组的前三个元素  
    slice := array[:3]  
  
    // 打印切片元素  
    fmt.Println(slice) // 输出: [1 2 3]  
  
    // 修改切片元素,也会修改底层数组对应位置的元素  
    slice[1] = 100  
    fmt.Println(array) // 输出: [1 100 3 4 5]  
}

指针的切片

  指针的切片是一个切片,但其元素是指针,指向某种数据类型的实例。这意味着每个元素都是一个地址,通过这个地址可以间接访问和操作实际的数据。指针的切片常用于需要存储大量数据且希望避免数据复制的场景,或者当需要在切片中存储可变大小的对象时。

  使用指针的切片可以节省内存空间,因为只需要存储指针而不是实际的数据。同时,通过指针可以方便地修改原始数据。然而,这也带来了额外的复杂性和风险,因为需要小心处理指针的解引用和内存管理。

  示例

package main  
  
import "fmt"  
  
type Person struct {  
    Name string  
    Age  int  
}  
  
func main() {  
    // 创建几个Person实例的指针  
    person1 := &Person{Name: "Alice", Age: 30}  
    person2 := &Person{Name: "Bob", Age: 25}  
  
    // 创建一个指针的切片,存储这些指针  
    people := []*Person{person1, person2}  
  
    // 通过指针修改Person实例的属性  
    people[0].Age = 31  
  
    // 打印修改后的Person实例  
    fmt.Println(people[0].Name, people[0].Age) // 输出: Alice 31  
}

结构体切片与结构体指针切片的区别

  1. 内存占用:

    • 结构体切片:每个元素都是结构体的一个完整副本,因此内存占用较大。

    • 结构体指针切片:每个元素只是一个指向结构体的指针,内存占用较小。但是,这并不意味着整体内存占用会小,因为还需要考虑实际结构体对象所占用的内存。

  2. 修改元素:

    • 结构体切片:修改切片中的一个元素,将直接修改该元素的值,不会影响其他切片或原始结构体对象。

    • 结构体指针切片:修改切片中的一个指针指向的元素,将影响所有指向该元素的指针。如果多个切片或变量指向同一个结构体对象,修改该对象的内容将影响所有引用。

  3. 初始化与赋值:

    • 结构体切片:可以直接初始化并赋值。

    • 结构体指针切片:需要先初始化结构体对象,然后将对象的地址赋值给切片。

  4. nil与空切片:

    • 对于结构体指针切片,nil切片和空切片(长度为0的切片)是不同的。nil切片没有分配底层数组,而空切片分配了底层数组但长度为0。

    • 对于结构体切片,通常不会讨论nil切片,因为切片总是与底层数组相关联。

能否直接遍历结构体切片并赋值给结构体指针切片

  不能直接遍历结构体切片并赋值给结构体指针切片。因为结构体切片中的元素是结构体的值,而结构体指针切片中的元素是指向结构体的指针。需要遍历结构体切片,并分别为每个元素创建指针,然后将这些指针添加到结构体指针切片中。

示例说明

  假设我们有一个Person结构体:

type Person struct {  
    Name string  
    Age  int  
}

  结构体切片的使用

// 创建并初始化一个Person结构体切片  
peopleSlice := []Person{  
    {"Alice", 30},  
    {"Bob", 25},  
}  
  
// 修改切片中的一个元素  
peopleSlice[0].Age = 31  
  
// 遍历并打印切片中的元素  
for _, person := range peopleSlice {  
    fmt.Println(person.Name, person.Age)  
}

  结构体指针切片的使用

// 创建并初始化一些Person结构体对象  
alice := Person{"Alice", 30}  
bob := Person{"Bob", 25}  
  
// 创建一个Person指针切片,并将结构体对象的地址添加到切片中  
peoplePtrSlice := []*Person{&alice, &bob}  
  
// 修改切片中的一个指针指向的元素  
peoplePtrSlice[0].Age = 31 // 这将改变alice的年龄,因为peoplePtrSlice[0]指向alice  
  
// 遍历并打印切片中的元素(通过解引用指针)  
for _, personPtr := range peoplePtrSlice {  
    fmt.Println(personPtr.Name, personPtr.Age)  
}  
  
// 如果想要遍历结构体切片并赋值给结构体指针切片,你需要这样做:  
peopleSlice := []Person{  
    {"Charlie", 28},  
    {"David", 35},  
}  
  
// 初始化一个空的Person指针切片,长度与peopleSlice相同  
peoplePtrSlice = make([]*Person, len(peopleSlice))  
  
// 遍历peopleSlice,为peoplePtrSlice分配新的指针  
for i, person := range peopleSlice {  
    // 创建person的一个副本,并获取其地址,然后赋值给peoplePtrSlice  
    peoplePtrSlice[i] = &Person{Name: person.Name, Age: person.Age}  
}  
  
// 现在peoplePtrSlice包含了指向peopleSlice中元素副本的指针

  在上面的示例中,peoplePtrSlice是通过遍历peopleSlice并创建每个元素的副本的地址来初始化的。如果你想要peoplePtrSlice中的指针指向peopleSlice中的相同对象(而不是副本),你需要确保这些对象是通过new函数或通过&操作符在堆上分配的,并且它们的地址被添加到peoplePtrSlice中。但是,在大多数情况下,你可能不希望这样做,因为这会导致切片之间共享相同的对象,从而可能引起意外的副作用。

能否直接遍历结构体指针切片并赋值给结构体切片

  不能直接遍历结构体指针切片并赋值给结构体切片。结构体指针切片中的元素是指向结构体的指针,而结构体切片中的元素是结构体的值。因此,如果你尝试直接将指针切片中的指针赋值给结构体切片,你会得到的是指针的值(即内存地址),而不是结构体对象本身的值。

  要遍历结构体指针切片并将指针指向的结构体对象赋值给结构体切片,你需要对每个指针进行解引用,获取其指向的结构体对象,然后将该对象赋值给结构体切片中的相应位置。

  下面是一个详细的示例说明和分析:

package main  
  
import (  
    "fmt"  
)  
  
// 定义Person结构体  
type Person struct {  
    Name string  
    Age  int  
}  
  
func main() {  
    // 初始化一些Person结构体对象,并获取它们的地址  
    alice := &Person{"Alice", 30}  
    bob := &Person{"Bob", 25}  
  
    // 创建一个Person指针切片  
    peoplePtrSlice := []*Person{alice, bob}  
  
    // 创建一个与peoplePtrSlice长度相同的Person结构体切片  
    peopleSlice := make([]Person, len(peoplePtrSlice))  
  
    // 遍历peoplePtrSlice,解引用指针并将结构体对象赋值给peopleSlice  
    for i, personPtr := range peoplePtrSlice {  
        peopleSlice[i] = *personPtr // 解引用指针,获取结构体对象  
    }  
  
    // 现在peopleSlice包含了peoplePtrSlice中指针指向的结构体对象的副本  
    fmt.Println(peopleSlice) // 输出: [{Alice 30} {Bob 25}]  
  
    // 修改peopleSlice中的元素,不会影响peoplePtrSlice或原始结构体对象  
    peopleSlice[0].Age = 31  
    fmt.Println(peopleSlice) // 输出: [{Alice 31} {Bob 25}]  
    fmt.Println(peoplePtrSlice) // 输出: [&{Alice 30} &{Bob 25}],peoplePtrSlice中的元素未改变  
}

  在这个示例中:

  1. 我们首先创建了两个Person结构体对象的指针alicebob
  2. 然后我们创建了一个包含这两个指针的peoplePtrSlice切片。
  3. 接着我们创建了一个与peoplePtrSlice长度相同的空Person结构体切片peopleSlice
  4. 在遍历peoplePtrSlice时,我们使用*personPtr来解引用指针,并将得到的结构体对象赋值给peopleSlice中的对应位置。
  5. 最后,我们验证了修改peopleSlice中的元素不会影响peoplePtrSlice或原始的结构体对象。

  需要注意的是,这样做会创建结构体对象的副本。如果你只是想引用原始的对象而不是它们的副本,你应该直接使用指针切片,而不是创建结构体切片。如果你确实需要结构体切片,并且想保持对原始对象的引用,那么你需要重新考虑你的数据结构设计,因为结构体切片本身不保存对原始对象的引用。

 

  

 

标签:指针,切片,Person,peopleSlice,go,peoplePtrSlice,结构
From: https://www.cnblogs.com/zjdxr-up/p/18132951

相关文章

  • 2024-04-13:用go语言,给定一个整数数组 `nums`, 请编写一个函数,返回一个新的数组 `counts
    2024-04-13:用go语言,给定一个整数数组nums,请编写一个函数,返回一个新的数组counts。满足以下条件:对于每个nums[i],counts[i]表示在nums[i]右侧且比nums[i]小的元素数量。输入:nums=[5,2,6,1]。输出:[2,1,1,0]。答案2024-04-13:来自左程云。灵捷3.5大体过程如下:给定......
  • 从Google网页中通过正则表达式获取json如何转换unicode对象
    场景:Google爬虫,获取下拉框搜索关键词,需要获取页面的里面的json字符串如下面:'{\\x22aa\\x22:{},\\x22abd\\x22:{\\x22abd\\x22:false,\\x22deb\\x22:false,\\x22det\\x22:false},\\x22async\\x22:{},\\x22attn\\x22:{},\\x22bgd\\x22:{\\x22ac\\x22:true,\\x......
  • VSCode使用Go插件
    本文更新于2023-12-26,使用VSCode1.85.1、Go插件v0.40.1。安装Go插件:使用Ctrl+Shift+X打开扩展面板,搜索“Go”,安装“Go”插件(GoforVisualStudioCode)。安装Go插件的依赖工具:因国内无法访问proxy.golang.org,故需自行配置模块代理。运行cmd。在cmd中运行setGOPROXY=h......
  • Go文档:Release History(发布历史)
    本文更新于2024-03-22。官方文档:https://go.dev/doc/devel/release目录泛型go1.22.0(2024-02-06)go1.21.0(2023-08-08)go1.20(2023-02-01)go1.19(2022-08-02)go1.18(2022-03-15)模块go1.17(2021-08-16)go1.16(2021-02-16)go1.15(2020-08-11)go1.14(2020-02-25)go1.13(......
  • 16、数据库加固-mongo 加固
    1.指定日志与数据库存放位置在配置文件中设置指向目录位置自建配置文件:vim/usr/local/mongodb/etc/mongodb.confdbpath=/data/dblogpath=/usr/local/mongodb/logs/mongdb.log2.更改默认端口自建配置文件:vim/usr/local/mongodb/etc/mongodb.confport=28888开......
  • go语言结构体使用小结
    转载请注明出处:在Go语言中,结构体(struct)是一种复合数据类型,它允许你将多个不同类型的字段组合成一个单一的类型。结构体为数据的封装和抽象提供了便利,使得数据组织更加清晰和易于管理。结构体的定义结构体的定义使用type关键字和struct类型,然后列出结构体的字段名和类型......
  • 52 Things: Number 42: Look at your C code for Montgomery multiplication above; c
    52Things:Number42:LookatyourCcodeforMontgomerymultiplicationabove;canyoudeterminewhereitcouldleaksidechannelinformation?52件事:数字42:看看上面蒙哥马利乘法的C码;你能确定它可能在哪里泄露侧通道信息吗? Thisisthelatestinaseriesofblog......
  • 【Django】
    https://www.djangoproject.com/MTVAnaconda:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?C=M&O=D创建和管理虚拟环境,这些环境可以包含不同版本的Python和安装的包,这在数据科学工具的使用中非常有用;Pip没有内置支持环境隔离,需要依赖其他工具,如virtualenv或venv来......
  • Go语言的100个错误使用场景(61-68)|并发实践
    目录前言9.并发实践9.1context的不恰当传播(#61)9.2开启一个协程但不知道何时关闭(#62)9.3在循环中没有谨慎使用协程(#63)9.4使用select和channel期待某个确定的行为(#64)9.5不使用用于通知的channel(#65)9.6不使用nilchannel(#66)9.7对channel的大小感到疑惑(#67)9.8忽视st......
  • Django Page not found at 问题排查
    1、确认请求路径是否正确,与setting.py中进行对比2、如果setting中路径是导入app中的路径,setting.py的路径需要是否正确,还要要看对应app下urls.py中的路径是否正确 3、如果是请求上传的图片,需要确认setting.py中配置文件路基没,如果配置了需要确认base_dir指向的路基是否正确......