在这里插入图片描述

  • 博主简介:努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:数据结构、Go,Java等相关知识。
  • 博主主页: @是瑶瑶子啦
  • 所属专栏: Go语言核心编程
  • 近期目标:写好专栏的每一篇文章

在这里插入图片描述

一、前言:

昨天写的【Golang项目实战】手把手教你写一个备忘录程序|附源码——建议收藏

我写第二个版本代码的时候遇到如下问题:

memos
memosmap[int]*Memo
memos[id].Title = newMemoTitle
memosidnewMemoTitle
memosmap[int]Memo
memo := memos[id]
memo.Title = newMemoTitle
memos[id] = memo
memosidmemomemomemosid

承接上文,为什么memos是map[int]Memo类型变量需要先将备忘录取出来,而不能memos[id].Head=newMemoHead这样直接赋值

memosmap[int]Memomemos[id]
memosmemosmap[int]Memo
memo := memos[id]
memo.Head = newMemoHead
memos[id] = memo
memosidmemomemoHeadmemosid

💡Summary

map[id]

(感觉熟悉Java的朋友和我一样可能还是不太清楚,可以看下面补充,结构体可以对应到Java中的类,类变量都是指针类型,所以像遇到这种值类型的结构体,我们才会如此不解)

二、不同语言的值类型、指针类型比较

值类型和指针类型在很多编程语言中都有类似的概念和特性,但具体实现和表达方式可能有所不同。

c++:
结构体可以定义为值类型指针类型,而且可以通过引用或指针来访问结构体的字段。在C++中,值类型的结构体在传递和复制时会进行 值拷贝-,而指针类型的结构体则只是复制指向结构体的指针。这和Go语言中值类型和指针类型的行为类似。

  • 值类型结构体和指针类型结构体:
// 值类型结构体
struct Point {int x;int y;
};// 指针类型结构体
struct Rect {Point* start;Point* end;
};
  • 值类型结构体传参可以用引用来接收(底层还是进行地址传递),不会进行值拷贝,通过形参可以影响实参
#include <iostream>
using namespace std;struct Point {int x;int y;
};void modifyPoint(Point& p) {p.x = 3;p.y = 4;
}int main() {Point p1 = { 1, 2 };modifyPoint(p1);cout << "p1: (" << p1.x << ", " << p1.y << ")" << endl;  // 输出 p1: (3, 4)return 0;
}

💬"值拷贝"?
值类型的结构体来说,它们的值包含了所有的成员字段,当一个值类型的结构体变量被赋值给另一个变量时,或者作为函数参数传递时,都会进行值拷贝。这意味着在内存中会创建一个新的结构体对象,并将原始结构体对象的值复制到新对象中,两个结构体对象之间互不影响。因此,如果我们修改其中一个值类型的结构体变量的属性值,不会影响到其他的变量。

new

Python:

在Python中,对象的内存管理是由解释器自动进行的,因此不需要手动进行内存分配和释放。Python中的对象都是指针类型,而且对象的引用计数机制可以自动进行垃圾回收。在Python中,可以使用赋值语句将一个对象的引用复制给另一个变量,这样两个变量都指向同一个对象。但是,如果对其中一个变量进行修改,就会创建一个新的对象,而另一个变量仍然指向原来的对象。

总的来说,值类型和指针类型是编程语言中一种基础概念和特性,不同的语言可能会有不同的实现和表达方式,但其本质是相似的。

Go语言中值类型、指针类型:

在Go语言中,值类型和引用类型都有各自的适用场景和运用方式。以下是一些常见的示例:

  1. 值类型的运用示例(1)
// 定义一个点(Point)结构体
type Point struct {X, Y int
}// 定义一个函数,用于计算两个点之间的距离
func distance(p1, p2 Point) float64 {dx := p2.X - p1.Xdy := p2.Y - p1.Yreturn math.Sqrt(float64(dx*dx + dy*dy))
}// 创建两个点并计算它们之间的距离
p1 := Point{1, 2}
p2 := Point{4, 6}
d := distance(p1, p2)
fmt.Println(d)
PointdistancedistancePoint
  1. 值类型的运用示例(2)
type Memo struct {Head string// other fields
}var memos map[string]Memofunc main() {memos = make(map[string]Memo)memo1 := Memo{Head: "Memo 1"}memos["1"] = memo1memo2 := memos["1"]memo2.Head = "Memo 2"fmt.Println(memos["1"].Head) // "Memo 1"
}

在上面的代码中,我们首先声明了一个map类型的变量memos,其中键值对的值类型为Memo。然后,我们创建了一个Memo结构体变量memo1,并将其添加到memos中。接着,我们通过memos[“1”]获取到了memo1的拷贝,并将其赋值给了memo2。然后,我们修改了memo2的Head属性,并打印了memos[“1”].Head的值。由于memos[“1”]中存储的是memo1的拷贝,因此memo2的修改并不会影响到memos[“1”],所以最终打印出来的结果是"Memo 1"。

相比之下,如果使用map[string]*Memo这样的类型来存储结构体指针,那么每次在map中存储一个值时,只会存储指向原始结构体的指针。这样,当修改map中的某个元素时,会直接影响原始的结构体变量。例如:

type Memo struct {Head string// other fields
}var memos map[string]*Memofunc main() {memos = make(map[string]*Memo)memo1 := Memo{Head: "Memo 1"}memos["1"] = &memo1memo2 := memos["1"]memo2.Head = "Memo 2"fmt.Println(memos["1"].Head) // "Memo 2"
}

在上面的代码中,我们首先声明了一个map类型的变量memos,其中键值对的值类型为*Memo。然后,我们创建了一个Memo结构体变量memo1,并将其地址添加到memos中。接着,我们通过memos[“1”]获取到了指向memo1的指针,并将其赋值给了memo2。然后,我们修改了memo2的Head属性,并打印了memos[“1”].Head的值。由于memos[“1”]中存储的是memo1的指针,因此memo2的修改直接影响到了memos[“1”],所以最终打印出来的结果是"Memo 2"。

因此,如果希望在map类型的变量中存储结构体,并且希望修改map中的元素会影响到原始的结构体变量,应该使用map[string]*Memo这样的类型来存储结构体指针。

  1. 引用类型的运用示例
// 定义一个切片(Slice)变量
nums := []int{1, 2, 3, 4, 5}// 定义一个函数,用于对切片进行排序
func sort(slice []int) {sort.Ints(slice)
}// 对切片排序并输出结果
sort(nums)
fmt.Println(nums)
numssortsort

总的来说,值类型和引用类型在Go语言中都有其各自的优势和适用场景。需要结合具体的应用场景和需求来选择合适的类型,并注意在使用值类型和引用类型时需要注意其特性和行为。


欢迎在评论区交流和留下你的想法和建议

如果对你有用,还请:💭评论+👍🏻点赞+⭐收藏+➕关注

在这里插入图片描述

  • Java岛冒险记【从小白到大佬之路】
  • LeetCode每日一题–进击大厂
  • 算法
  • C/C++
  • Go语言核心编程
  • 数据结构