golang 遍历结构体中结构体与字节数组能相互转化么

当前位置:
微信扫一扫分享到朋友圈
# 结构体和包中的类型或基础类型定义方法## 1、对结构体定义方法首先看下面这个例子:```golangpackage mainimport (& & &fmt&& & &math&)type Vertex struct {& & X, Y float64}func (v *Vertex) Abs() float64 {& & return math.Sqrt(v.X*v.X + v.Y*v.Y)}func main() {& & v := &Vertex{3, 4}& & fmt.Println(v.Abs())& & fmt.Println(v,*v)& &&& & x := Vertex{3, 4}& & fmt.Println(x.Abs())& & fmt.Println(x) &&}```Go 没有类。然而,仍然可以在结构体类型上定义方法。方法接收者 出现在 func 关键字和方法名之间的参数中--- & &(v *Vertex)```golangfunc (v *Vertex) FunName() float64 {& & & //&}```## 2、对包中的任意类型定义任意方法 &对包中的 任意 类型定义任意方法,而不仅仅是针对结构体。不能对来自其他包的类型或基础类型定义方法。----- &(f MyFloat)如下示例:```golangpackage mainimport (& & &fmt&& & &math&)type MyFloat float64func (f MyFloat) Abs() float64 {& & if f & 0 {& & & & return float64(-f)& & }& & return float64(f)}func main() {& & f := MyFloat(-math.Sqrt2)& & fmt.Println(f.Abs())}```下面用如下这个例子来区二者区别以及用法:```golangpackage mainimport (& & &fmt&& & &math&)// 普通类型type MyFloat float64func (f MyFloat) Abs() float64 {& & if f & 0 {& & & & return float64(-f)& & }& & return float64(f)}func (f *MyFloat) P() float64{& & if *f & 0 {& & & & return float64(-*f)& & }& & return float64(*f)}// 结构体type Vertex struct {& & X, Y float64}func (v *Vertex) Abs() float64 {& & return math.Sqrt(v.X*v.X + v.Y*v.Y)}func (v Vertex) Scale(f float64) {& & v.X = v.X * f& & v.Y = v.Y * f}func main() {& & // 基础类型的初始化和调用方式,注意用()而不是{}& & f := MyFloat(-math.Sqrt2)& & fmt.Println(f.Abs(),f.P())& &&& & /*& 错误调用方式1:& & f1 := &MyFloat(-math.Sqrt2)& & fmt.Println(*f.Abs(),*f.P()) 错误调用方式2: f1 := &MyFloat{-math.Sqrt2}& & fmt.Println(*f.Abs(),*f.P()) 错误调用方式3: f1 := MyFloat{-math.Sqrt2}& & fmt.Println(f.Abs(),f.P())& & */& & v := &Vertex{3, 4}& & fmt.Println(v, *v,&v,v.Abs())& & v.Scale(5)& & fmt.Println(v, *v,&v,v.Abs())& &&& & v1 := Vertex{6, 7}& & fmt.Println(v1,&v1, v1.Abs())& & v1.Scale(8)& & fmt.Println(v1, v1.Abs())}// 输出:/*1.1&{3 4} {3 4} 0x&{3 4} {3 4} 0x{6 7} &{6 7} 9.887{6 7} 9.887*/```**注意区别:**```golangfunc (v *Vertex) Abs() float64&func (v Vertex) Abs() float64&```## 3、注意两者区别:& * func (v *Vertex) Abs() float64&& & 调用方法时传递的是对象的实例的指针,即可改变对象的值;& * func (v Vertex) Abs() float64&调用方法时传递的是对象的实例的一个副本,即不可改变对象的值;总结:对象的实例针对数据操作时必须定义为指针的类型,然后才能传递正确的地址,否则v参数只是对象的一个副本,下面这个实例则可佐证此观点:```golangpackage mainimport (& & &fmt&& & &math&)// 普通类型type MyFloat float64func (f MyFloat) Abs() &{& & if f & 0 {& & & & f = MyFloat(float64(-f))& & }
f = MyFloat(float64(f))}func (f *MyFloat) Abs_1() {& & if *f & 0 {& & & & *f = MyFloat(float64(-*f))& & } *f = MyFloat(float64(*f))}// 结构体type Vertex struct {& & X, Y float64}func (v Vertex) Scale(f float64) {& & v.X = v.X * f& & v.Y = v.Y * f}func (v *Vertex) Scale_1(f float64) {& & v.X = v.X * f& & v.Y = v.Y * f}func main() {& & // 基础类型的初始化和调用方式,注意用()而不是{}& & f := MyFloat(-math.Sqrt2)& & fmt.Println(f, &f)& & f.Abs()& & fmt.Println(f, &f)& & f.Abs_1()& & fmt.Println(f, &f)& &&& &&& & v := &Vertex{3, 4}& & fmt.Println(v, *v,&v)& & v.Scale(5)& & fmt.Println(v, *v,&v)& & v.Scale_1(5)& & fmt.Println(v, *v,&v)& &&& & v1 := Vertex{6, 7}& & fmt.Println(v1,&v1)& & v1.Scale(8)& & fmt.Println(v1, &v1)& & v1.Scale_1(8)& & fmt.Println(v1, &v1)}// 输出结果:/*-1.00168-1.001681.00168&{3 4} {3 4} 0x&{3 4} {3 4} 0x&{15 20} {15 20} 0x{6 7} &{6 7}{6 7} &{6 7}{48 56} &{48 56}*/```总结:golang隐式传递指针,但是不隐式定义指针,此坑需同学们注意。----------------------------------------#==== golang-python学习心得 ====微信公众号:golang-python &私人微信ID:fuhao1121网址:http://fuhao715.github.ioQQ:&编程学习心得轻松学编程&回复:『 p 』查看python课程回复回复:『 g 』查看golang课程回复回复:『 m 』查看项目管理回复:『 w 』查看其他文章&点击&阅读全文&进入http://fuhao715.github.io
分享给好友
分享到微信朋友圈:
第一步 打开微信底部扫一扫
第二步 扫下面的文章二维码
第三步 右上角点击转发
相关文章Relevant
■ 点击上面蓝字一键关注 ▲QIBU生活微刊建议在WIFI下观看,土豪请随意~~1、每一次接吻 会消耗体内至少12个卡路里科学家指出:...
我是主播 贝妮~(微信号:Voaoao)每天提供最热门、最火爆、最精彩的视频!口味有点儿重喔~笑死!笑死!笑死!如果觉得这些还...
【最费脑力的14部电影】《盗梦空间》、《记忆裂痕》、《生死停留》、《死亡幻觉》、《禁闭岛》、《穆赫兰道》、《蝴蝶效应》、...
现如今,飞机以舒适、方便与节省时间等原因成为出行首选的交通方式之一.可你是否知道,为何不能喝飞机上的冲泡茶饮,又为何在...
感知CG,感触创意,感受艺术,感悟心灵 在CG世界的一期中我们展示了 Vince Low的一部分作品,今天再次翻看CG网站时发现他的...
因女儿未出世便患肿瘤,柴静离职后首发雾霾调查.雾霾是什么?它从哪儿来?我们怎么办?看完这些,才知道雾霾的真相.震撼!震...2013年12月 Java大版内专家分月排行榜第二
2013年8月 Java大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。Golang Array 数组 和 Slice 切片
一 数组简介
数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度。
注意:和C中的数组相比,又是有一些不同的
1. Go中的数组是值类型,换句话说,如果你将一个数组赋值给另外一个数组,那么,实际上就是将整个数组拷贝一份
2. 如果Go中的数组作为函数的参数,那么实际传递的参数是一份数组的拷贝,而不是数组的指针。这个和C要区分开。因此,在Go中如果将数组作为函数的参数传递的话,那效率就肯定没有传递指针高了。
3. array的长度也是Type的一部分,这样就说明[10]int和[20]int是不一样的。array的结构用图示表示是这样的:
len表示数组的长度,后面的int储存的是实际数据
二 数组初始化
初始化数组的初始化有多种形式,查看示例代码
[5] int {1,2,3,4,5}
长度为5的数组,其元素值依次为:1,2,3,4,5
[5] int {1,2}
长度为5的数组,其元素值依次为:1,2,0,0,0 。在初始化时没有指定初值的元素将会赋值为其元素类型int的默认值0,string的默认值是""
[...] int {1,2,3,4,5}
长度为5的数组,其长度是根据初始化时指定的元素个数决定的
[5] int { 2:1,3:2,4:3}
长度为5的数组,key:value,其元素值依次为:0,0,1,2,3。在初始化时指定了2,3,4索引中对应的值:1,2,3
[...] int {2:1,4:3}
长度为5的数组,起元素值依次为:0,0,1,0,3。由于指定了最大索引4对应的值3,根据初始化的元素个数确定其长度为5赋值与使用
三 数组的访问
数组通过下标访问元素,可修改其元素值
arr :=[...] int {1,2,3,4,5}
arr[4]=arr[1]+len(arr)
//arr[4]=2+5
通过for遍历数组元素
arr := [5]int{5, 4, 3}
for index, value := range arr {
fmt.Printf("arr[%d]=%d \n", index, value)
for index := 0; index < len(arr); index&#43;&#43; {
fmt.Printf("arr[%d]=%d \n", index, arr[index])
数组是&#20540;类型,将一个数组赋&#20540;给另一个数组时将复制一份新的元素
arr2 := [5]int{1, 2}
arr5 := arr2
arr5[0] = 5
arr2[4] = 2
fmt.Printf(" arr5= %d \n arr2=%d \n arr5[0]==arr2[0]= %s \n", arr5, arr2, arr5[0] == arr2[0])
arr5=[5 2 0 0 0]
arr2=[1 2 0 0 2]
arr5[0]==arr2[0]= false
四 切片简介
数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型Slices切片(“动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指已经被赋过&#20540;的最大下标&#43;1,可通过内置函数len()获得。容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。切片是引用类型,因此在当传递切片时将引用同一指针,修改&#20540;将会影响其他的对象。
五 切片的使用
Slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。
// 和声明array一样,只是少了长度
var fslice []int
接下来我们可以声明一个slice,并初始化数据,如下所示:
slice := []byte {'a', 'b', 'c', 'd'}
slice可以从一个数组或一个已经存在的slice中再次声明。slice通过array[i:j]来获取,其中i是数组的开始位置,j是结束位置,但不包含array[j],它的长度是j-i。
// 声明一个含有10个元素元素类型为byte的数组
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 声明两个含有byte的slice
var a, b []byte
// a指向数组的第3个元素开始,并到第五个元素结束,
a = ar[2:5]
//现在a含有的元素: ar[2]、ar[3]和ar[4]
// b是数组ar的另一个slice
b = ar[3:5]
// b的元素是:ar[3]和ar[4]
注意slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。
它们的数据结构如下所示
slice有一些简便的操作
slice的默认开始位置是0,ar[:n]等价于ar[0:n]slice的第二个序列默认是数组的长度,ar[n:]等价于ar[n:len(ar)]如果从一个数组里面直接获取slice,可以这样ar[:],因为默认第一个序列是0,第二个是数组的长度,即等价于ar[0:len(ar)]
下面这个例子展示了更多关于slice的操作:
// 声明一个数组
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 声明两个slice
var aSlice, bSlice []byte
// 演示一些简便操作
aSlice = array[:3] // 等价于aSlice = array[0:3] aSlice包含元素: a,b,c
aSlice = array[5:] // 等价于aSlice = array[5:10] aSlice包含元素: f,g,h,i,j
aSlice = array[:]
// 等价于aSlice = array[0:10] 这样aSlice包含了全部的元素
// 从slice中获取slice
aSlice = array[3:7]
// aSlice包含元素: d,e,f,g,len=4,cap=7
bSlice = aSlice[1:3] // bSlice 包含aSlice[1], aSlice[2] 也就是含有: e,f
bSlice = aSlice[:3]
// bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是含有: d,e,f
bSlice = aSlice[0:5] // 对slice的slice可以在cap范围内扩展,此时bSlice包含:d,e,f,g,h
bSlice = aSlice[:]
// bSlice包含所有aSlice的元素: d,e,f,g
slice是引用类型,所以当引用改变其中元素的&#20540;时,其它的所有引用都会改变该&#20540;,例如上面的aSlice和bSlice,如果修改了aSlice中元素的&#20540;,那么bSlice相对应的&#20540;也会改变。
从概念上面来说slice像一个结构体,这个结构体包含了三个元素:
一个指针,指向数组中slice指定的开始位置长度,即slice的长度
最大长度,也就是slice开始位置到数组的最后位置的长度
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
Slice_a := Array_a[2:5]
上面代码的真正存储结构如下图所示
对于slice有几个有用的内置函数:vcD4KPHVsPgo8bGk+PGNvZGU+bGVuPC9jb2RlPiC78cihPGNvZGU+c2xpY2U8L2NvZGU+tcSzpLbIPGxpPjxjb2RlPmNhcDwvY29kZT4gu/HIoTxjb2RlPnNsaWNlPC9jb2RlPrXE1+6088jdwb88bGk+PGNvZGU+YXBwZW5kPC9jb2RlPiDP8jxjb2RlPnNsaWNlPC9jb2RlPsDvw+bXt7zT0ru49rvy1d+24Lj21KrL2KOsyLu687e1u9jSu7j2us08Y29kZT5zbGljZTwvY29kZT7Su9H5wODQzbXEPGNvZGU+c2xpY2U8L2NvZGU+PGxpPjxjb2RlPmNvcHk8L2NvZGU+ILqvyv08Y29kZT5jb3B5PC9jb2RlPrTT1LQ8Y29kZT5zbGljZTwvY29kZT61xDxjb2RlPnNyYzwvY29kZT7W0Li01sbUqsvYtb3Ev7HqPGNvZGU+ZHN0PC9jb2RlPqOssqLH0re1u9i4tNbGtcTUqsvYtcS49sr9CgrXoqO6PGNvZGU+YXBwZW5kPC9jb2RlPrqvyv274bjEseQ8Y29kZT5zbGljZTwvY29kZT7L+dL908O1xMr91+m1xMTayN2jrLTTtvjTsM/stb3S/dPDzazSu8r91+m1xMbky/w8Y29kZT5zbGljZTwvY29kZT6howogtau1sTxjb2RlPnNsaWNlPC9jb2RlPtbQw7vT0Mqj0+C/1bzko6i8tDxjb2RlPihjYXAtbGVuKQogPT0gMDwvY29kZT6jqcqxo6y0y8qxvau2r8yst9bF5NDCtcTK/dfpv9W85KGjt7W72LXEPGNvZGU+c2xpY2U8L2NvZGU+yv3X6da41eu9q9a4z/LV4rj2v9W85KOstvjUrcr91+m1xMTayN29q7Gjs9ayu7Hko7vG5Mv80v3Tw7TLyv3X6bXEPGNvZGU+c2xpY2U8L2NvZGU+1PKyu8rc07DP7KGjILP1yry7r8fQxqy/ydLUzai5/cr91+nAtLP1yry7r6Os0rK/ydLUzai5/cTa1sO6r8r9bWFrZSgps/XKvLuvCiAus/XKvLuvyrFsZW49Y2FwLNTa17e809Sqy9jKscjnufvI3cG/Y2FwsrvX48qxvauwtGxlbrXEMrG2wKnI3SCy6b+0yr7A/bT6wuujrNTaz9/Uy9DQyr7A/bT6wus8YnI+Cjxicj4Kwfkgs6PTw7XEs/XKvLuvt723qKO6CgogICAgICAgcyA6PVtdIGludCB7MSwyLDMgfTxicj4K1rG907P1yry7r8fQxqyjrFtdse3KvsrHx9DGrMDg0M2jrHsxLDIsM32z9cq8u68mIzIwNTQwO9LAtM7KxzEsMiwzLsbkY2FwPWxlbj0zPGJyPgogICAgIAoKICAgICAgIHMgOj0gYXJyWzpdPGJyPgqz9cq8u6/H0MascyzKx8r91+lhcnK1xNL908M8YnI+CiAgICAgCgogICAgICBzIDo9IGFycltzdGFydEluZGV4OmVuZEluZGV4XTxicj4KvathcnLW0LTTz8Kx6nN0YXJ0SW5kZXi1vWVuZEluZGV4LTEgz8K1xNSqy9i0tL2ozqrSu7j20MK1xMfQxqw8YnI+CiAgICAgCgogICAgICBzIDo9IGFycltzdGFydEluZGV4Ol08YnI+CsixyqFlbmRJbmRleMqxvaux7cq+0rvWsbW9YXJytcTX7rrz0ru49tSqy9g8YnI+CiAgICAgCgogICAgIHMgOj0gYXJyWzplbmRJbmRleF08YnI+CsixyqFzdGFydEluZGV4yrG9q7Htyr6002FycrXEtdrSu7j21KrL2L+qyrw8YnI+CiAgICAgCgogICBzMSA6PSBzW3N0YXJ0SW5kZXg6ZW5kSW5kZXhdPGJyPgrNqLn9x9DGrHOz9cq8u6/H0MasczE8YnI+CiAgIAoKICAgIHMgOj1tYWtlKFtdaW50LGxlbixjYXApCgrNqLn9xNrWw7qvyv1tYWtlKCmz9cq8u6/H0MascyxbXWludCCx6sq2zqrG5NSqy9jA4NDNzqppbnS1xMfQxqw8YnI+Cjxicj4KuLMmIzIwNTQwO9PryrnTw8fQxqzKx9L908PA4NDNo6zU2sq508PKsdDo0qrXotLixuSy2df3oaPH0Masv8nS1M2ouf3E2tbDuq/K/WFwcGVuZChzbGljZSBbXVR5cGUsZWxlbXMgLi4uVHlwZSnXt7zT1KrL2KOsZWxlbXO/ydLUysfSu8XFdHlwZcDg0M21xMr9vt2jrNKyv8nS1MrHc2xpY2Us0vLOqte3vNO1xNK7uPbSu7j2tcTUqsvYo6zS8rTLyOe5+72r0ru49nNsaWNl17e807W9we3Su7j2c2xpY2XW0NDo0qq0+MnP"...",这样才能表示是将slice中的元素依次追加到另一个slice中。另外在通过下标访问元素时下标不能超过len大小,如同数组的下标不能超出len范围一样。
s :=append(s,1,2,3,4)
s :=append(s,s1…)
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'理解Golang中的数组(array)、切片(slice)和map
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了理解Golang中的数组(array)、切片(slice)和map,本文先是给出代码,然后一一分解,并给出一张内图加深理解,需要的朋友可以参考下
我比较喜欢先给出代码,然后得出结论
package main
func main() {
&&& arr := [...]int{1, 2, 3}
&&& //打印初始的指针
&&& fmt.Printf("the pointer is : %p \n", &arr)
&&& printPointer(arr)
func printPointer(any interface{}) {
&&& fmt.Printf("the pointer is : %p \n", &any)
1 the pointer is : 0xc
2 the pointer is : 0xc
package main
func main() {
&&& arr := make([]int, 3)
&&& //打印初始的指针
&&& fmt.Printf("the pointer is : %p \n", arr)
&&& printPointer(arr)
func printPointer(any interface{}) {
&&& fmt.Printf("the pointer is : %p \n", any)
1 the pointer is : 0xc
2 the pointer is : 0xc
package main
func main() {
&&& arr := make(map[int]string)
&&& //arr := [3]int{1, 2, 3}
&&& //打印初始的指针
&&& fmt.Printf("the pointer is : %p \n", arr)
&&& printPointer(arr)
func printPointer(any interface{}) {
&&& fmt.Printf("the pointer is : %p \n", any)
1 the pointer is : 0xc
2 the pointer is : 0xc
由此,我们看到数组本身传过去的是值,传到函数之后,被开辟了另外一个空间。
因为数组就是他本身。这一句好像不太好理解。
这是切片 arr := make([]int, 3)& 而arr 本身不是一个数组,至少不是我们所想要的指向的一个数组。只是arr里有一个地址指向数组。
这么举个例子:
arr := [...]int{1,2,3,4,5} 这是一个数组,懂得go语言的都明白。& arr本身就是数组
arrSlice := arr[0:5]& 这是一个切片。 打印所得的值是一样的,和上面。& arrSlice本身不是数组,只是arrSlice本身有一个值是指向arr的指针。
切片是指一个结构体,大体结构像这样:
struct slice{
&&&& ptr *Elem
&&& len int
&&& cap int
也就是说,上面的arrSlice其实是一个结构体。里面有一个属性 ptr指向数组 arr
其实arrSlice也是传到函数里,也是进行了复制。但是尽管传过去是一个复制的结构体,他的属性ptr,没有变。还是一个指向原数组的指针。
下面的例子见证他自己传过去,是一个复制的过程:
package main
func main() {
&&& arrSlice := make([]int, 4)
&&& fmt.Printf("the pointer is : %p \n", arrSlice)
&&& fmt.Printf("the pointer is : %p \n", &arrSlice) //这是arrSlice本身的指针,也就是结构体的指针
&&& printPointer(arrSlice)
func printPointer(any interface{}) {
&&& fmt.Printf("the pointer is : %p \n", any)
&&& fmt.Printf("the pointer is : %p \n", &any) //打印传过来的结构体arrSlice的指针
the pointer is : 0xc
the pointer is : 0xc
the pointer is : 0xc
the pointer is : 0xc
第1、3个的打印是打印这个结构体的ptr属性,也就是指向数组的指针。
其实这个结构体传到函数里,是一个复制的过程,第2、4的指针不一样。
大家在对照下面的图片理解一下:
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 golang 结构体指针 的文章

 

随机推荐