python调用golang 数组_Golang数据类型 数组(arry)

本文探讨了Go语言中的数组和切片与Python中列表的区别。Go中的数组是可变的,但赋值时会复制整个数组,而Python的列表是引用类型,修改不会复制。此外,Go的切片会产生新的内存,不同于数组的引用。文章通过示例代码展示了两种语言中数据类型的特性,并讨论了内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

前面学习了Go数据类型中的数字、字符串,下面看看Go中是否有Python中的list、dict等复合数据类型?

需要注意的是在Go中数组是可变类型+值(拷贝)类型,而go中切片是引用类型;

数组声明之后它里面的元素是可以被修改,如果把1个数组变量引用到1个新的变量,那么这个新的变量会重新拷贝一份旧数组的数组。

Python中的list是可变+引用数据类型

llist1 = ["A", "B", "C"]

llist2=llist1

llist1[0]= "a"llist2[2] = "b"

print(llist1, id(llist1))print(llist2, id(llist2))"""['a', 'B', 'b'] 42775624

['a', 'B', 'b'] 42775624"""

Python的list可变+引用

Golang中的arry是可变+拷贝数据类型

package main

import"fmt"func main() {

arry1 := [3]string{"A", "B", "C"} //注意声明arry变量时不要忘记[指定长度],否则声明的是slice变量

arry2 :=arry1

arry1[0] = "a"arry2[1] = "b"

//说明go中的arry不是引用类型,单属于可变数控类型可以原处修改

fmt.Printf("%v %p\n", arry1, &arry1)

fmt.Printf("%v %p\n", arry2, &arry2)

}/*[a B C] 0xc000062330

[A b C] 0xc000062360*/

Golang的arry可变+拷贝

Python的list切片之后会开辟1开新的内存生产1个新的list数据类型

nameList=["张","根"]

firstName=nameList[0]

lastName=nameList[1]print(firstName)print(lastName)#Python的list切片会开辟1块新的内存,创建1个新的列表。

nameSlice=nameList[0:2]

nameSlice[0]="Martin"nameSlice[1]="Zhang"

print(nameList,nameSlice)print(type(nameList),type(nameSlice))print(id(nameList),id(nameSlice))'''张

['张', '根'] ['Martin', 'Zhang']

42632648 42632712'''

Python的list切片

Golang的arry切片之后会开辟1个新的内存生成1个slice数据类型

package main

import ("fmt"

"reflect")

func main() {

nameArry:=[2]string{"张","根"}//1.获取数组的长度

fmt.Println(len(nameArry))//2.通过数组索引取值

firstName:=nameArry[0]

lastName:=nameArry[1]

fmt.Println(firstName)

fmt.Println(lastName)//3.数组组切片

nameSlice:=nameArry[0:2]

nameSlice[0]="Martin"nameSlice[1]="Zhange"fmt.Println(nameArry,nameSlice)//[Martin Zhange] [Martin Zhange]

fmt.Println(reflect.TypeOf(nameArry),reflect.TypeOf(nameSlice)) //[2]string(数组类型)-------- []string(切片类型)

fmt.Printf("切片之前的内存地址:%p,切片之后的slice内存地址:%p--",&nameArry,nameSlice)

}

Golang的Arry切片

package main

import "fmt"

func main() {

//声明1个字符串变量

var name string

fmt.Println(name)

//声明1个数组变量

var a1 [3]int

fmt.Println(a1)

//声明1个切片类型的变量

var s1 []int

fmt.Println(s1 == nil)

//声明二维数组

var a3 [3][3]int

//对二维数组进行初始化

a3 = [3][3]int{

[3]int{1, 2, 3},

[3]int{4, 5, 6},

[3]int{7, 8, 8},

}

fmt.Println(a3)

//

a4 := [3]int{1, 2, 3}

a5 := modifyArry(a4)

fmt.Println(a4)

fmt.Println(a5)

s2 := []string{"河北", "保定", "唐县"}

s3 := modifySlice(s2)

fmt.Println(s2)

fmt.Println(s3)

}

//数组是值类型:修改数组时,会复制 1个新的数组让我们修改

func modifyArry(a1 [3]int) (ret [3]int) {

a1[0] = 100

return a1

}

//切片是引用类型:修改切片时,不会复制1个新的切片让我们修改(修改原来的)

func modifySlice(s2 []string) (ret2 []string) {

s2[0] = "河北省"

return s2

}

数组

数组就是存放同1种数据基本数据类型(数值,字符、字符串、布尔值)元素的容器。

Go中的数组有一下特点:

在声明arry变量时就要声明arry的长度、容器内存放元素的数据类型;

数组的长度是数据类型的1部分,所以2个长度不同arrr,即使他们都属于数组,但2者的数据类型完全不一致,所以2者无法相互比较和赋值。

数组如果没有初始化里面的元素默认为0值(bool=false,int or float=0, string=空字符串)

数组的声明和初始化

package main

import "fmt"

func main() {

//数组:存放同1中基础数据类型的容器

//声明1个长度为3的数组,里面存放bool数据类型

var arry1 [3]bool

var arry2 [4]bool

var arry3 [3]bool

fmt.Printf("arry1:%T arry2:%T arry3:%T\n", arry1, arry2, arry3)

fmt.Println(arry1 == arry3)

//初始化方式1:

arry1 = [3]bool{true, true, true}

fmt.Println(arry1) //[true true true]

//初始化方式2:[...]自动推算数组的长度

arry4 := [...]int{1, 2, 3, 4}

fmt.Println(arry4)

//初始化方式3:利用默认值

arry5 := [5]int{12, 13}

fmt.Println(arry5) //[12 13 0 0 0]

//初始化方式4:根据索引指定arry中的元素

arry6 := [5]int{0: 1, 4: 6}

fmt.Println(arry6)//[1 0 0 0 6]

}

遍历数组

package main

import ("fmt"

"reflect")

func main() {

nameArry := [2]string{"张", "根"}//1.获取数组的长度

fmt.Println(len(nameArry))//2.通过数组索引取值

firstName := nameArry[0]

lastName := nameArry[1]

fmt.Println(firstName)

fmt.Println(lastName)//3.数组组切片

nameSlice := nameArry[0:2]

nameSlice[0] = "Martin"nameSlice[1] = "Zhange"fmt.Println(nameArry, nameSlice)//[Martin Zhange] [Martin Zhange]

fmt.Println(reflect.TypeOf(nameArry), reflect.TypeOf(nameSlice)) //[2]string(数组类型)-------- []string(切片类型)

fmt.Printf("切片之前的内存地址:%p,切片之后的slice内存地址:%p--\n", &nameArry, nameSlice)//2.循环数组

fmt.Println(nameArry)for i := 0; i < len(nameArry); i++{

fmt.Println(i, nameArry[i])

}for item :=range nameArry {

fmt.Println(item)

}for index :=range nameArry {

fmt.Println(index)

}for index, item :=range nameArry {

fmt.Println(index, item)

}

}

遍历数组

多维数组

多维数组就是数组里面嵌套数组

package main

import (

"fmt"

)

func main() {

//定义多维数组

a1 := [3][2]int{{1, 2}, {1, 3}, {1, 4}}

fmt.Println(a1) //[[1 2] [1 3] [1 4]]

//遍历多维数组

for _, v := range a1 {

for _, v1 := range v {

fmt.Println(v1)

}

}

}

数组的内存管理机制

Golang字符串类型存储的机制

我们在Golang中声明的字符串类型变量,编译器不会直接存储该字符串的值。

而是先开辟1块内存把字符串的值存储起来,然后开辟1块内存把这个字符串的指针(8个字节)和长度(8个字节)存储起来赋予变量。

为什么要这样存储1个字符串呢?额外开辟1块存储指针和长度的内存空间。

我感觉这是是为了字符串被放到到Arry或Slice之后的查询效率而做的铺垫。

1.数组的内存地址是连续的

2.数组的内存地址=数组中第1个元素的内存地址

这种设计可以让我们快速的从1个元素获取到数组中最后1个元素,查询效率大大提升。

既然声明1个数组即开辟了1块连续的内存,对Arry中的item进行顺序存储,那么Arry的item含有字符串呢?

字符串可能是英文/汉字它们占用内存的规格可不一致啊!既然如此那我就同一一下规格!

3.声明1个字符串数组时,开启一段连续的内存之后,(并不会在这段连续的内存上直接存储字符串的值,而是存储字符串值的指针(占4个字节)和长度(占4字节)=16个字节。这也是Golang中字符串数据类型的存储机制,连续的内存+指针=加快查询效率...)

这样Arry中每1个元素对这段连续内存的使用都有了固定的规格,节约了Arry对内存空间占用。

随意字符串存储时增加了额外的空间去存储指针和长度,但是加速了查询效率。用空间换时间吧!

package main

import"fmt"

//1.数组的内存是连续的//2.因为数组的内存是连续的,所以数组的内存地址就是数组里第1个元素的内存地址。

func main() {

numbers := [3]int8{11, 22, 33}

fmt.Printf("%p\n", &numbers) //0xc00000a0a8

fmt.Println(numbers) //[11 22 33]

fmt.Printf("%p\n", &numbers[0]) //0xc00000a0a8

fmt.Printf("%p\n", &numbers[1]) //0xc00000a0a9

fmt.Printf("%p\n", &numbers[2]) //0xc00000a0aa

numbers32 := [3]int32{11, 22, 33}

fmt.Printf("%p\n", &numbers32) //0xc00011e0b4

fmt.Println(numbers) //[11 22 33]

fmt.Printf("%p\n", &numbers32[0]) //0xc00011e0b4

fmt.Printf("%p\n", &numbers32[1]) //0xc00011e0b8

fmt.Printf("%p\n", &numbers32[2]) //0xc00011e0bc

var names = [2]string{"张根", "Martin"}

fmt.Printf("%p\n", &names) //0xc0000044c0

fmt.Println(names) //[张根 Martin]

fmt.Printf("%p\n", &names[0]) //0xc000114460

fmt.Printf("%p\n", &names[1]) //0xc000114470

}

Arry内存管理机制

Go中多维数组是数值类型不是引用类型

值类型:就是重新开辟新的内存,与引用类型相反

package main

import (

"fmt"

)

func main() {

//arry数值类型辩证

a1 := [...]string{"河北", "河南", "山东"}

a2 := a1

a1[len(a1)-1] = "山西"

fmt.Println(a1) //[河北 河南 山西]

fmt.Println(a2) //[河北 河南 山东]

}

练习题

package main

import (

"fmt"

)

func main() {

//1.求数组[1, 3, 5, 7, 8]所有元素的和

arr1 := [...]int{1, 3, 5, 7, 8}

var sum int

for _, v := range arr1 {

sum += v

}

fmt.Println(sum)

/*找出数组中和为指定值的两个元素的下标,比如从数组[1, 3, 5, 7, 8]中找出和为8的两个元素的下标分别为(0,3)和(1,2)*/

for i := 0; i < len(arr1); i++ {

for j := i + 1; j < len(arr1); j++ {

if arr1[i]+arr1[j] == 8 {

fmt.Printf("%d %d\n", i, j)

}

}

}

}

package main

import"fmt"

/*1.Go语言的int占多少个字节?

答:取决于你的操作系统 32位 4个字节,64位8个字节

2.整型中有符号和无符号是什么意思?

答:所谓有符号是使用1个位表示征服性质,因为使用第1位表示正负性质,所以有符号整型可表示的正数范围比较小,无符号整型表示的整数范围比较大!

3.整型可以表示的最大范围是

答:0-2**64,超出之后使用bigint包

4.什么是nil

答:nil就是空的数据

5.十进制是以整型的方式存在,其他其他进制以字符串的形式存在?如何实现进制之间的转换?

答:在golang中10进制是以整型存在,其他进制(二进制、八进制、十六进制)都是以字符串的形式存在

bynaryNumber:=strconv.FormatInt(int64(29),2)//十进制转二进制

octalNumber:=strconv.FormatInt(int64(29),8)//十进制转八进制

hexaDecimal:=strconv.FormatInt(int64(29),16)//十进制转八进制

fmt.Println(bynaryNumber,octalNumber,hexaDecimal)

fmt.Println(strconv.ParseInt(hexaDecimal,16,32))

6.简述如下代码的意义:var v1 int|var v2 *int var v3=new(int)

var v1 int //开辟1块个内存+内存初始化值位0,v1指向该内存地址,打印显示0

fmt.Println(v1)

v2:=999 //开辟1块个内存+内存初始化值设置为999,v2指向该内存地址,打印显示0

fmt.Println(v2)

var v3 *int

fmt.Printf("编译器开辟1块名为:%p的内存 存储了1个%p的空指针,空指针指向了nil(并没有初始化)\n",&v3,v3)

v4:=new(int)

fmt.Printf("编译器开辟1块名为:%p的内存 存储了1个指针%p,指针指向%p内存这块内存上存了值%d\n",&v4,v4,&*v4,*v4)

7.浮点型为什么无法精准表示小数?

答:这取决于 浮点型的小数部。小数部分 分转换成二进制时得不出1就这个浮点型就无法精确表达。

8.如何使用第3方包decimal?

答:

var v1 =decimal.NewFromFloat(0.0000019)

var v2 =decimal.NewFromFloat(0.298766)

var v3 =v1.Add(v2)

var v4 =v3.Sub(v2)

var v5 =v4.Mul(v2)

var v6 =v4.Div(v1)

fmt.Println(v3)

fmt.Println(v4)

fmt.Println(v5)

fmt.Println(v6)

var price=decimal.NewFromFloat(3.6615926)

fmt.Println(price.Round(1)) //保留小数点后1位自动四舍五入

fmt.Println(price.Truncate(2))//保留小数点后2位不需要四舍五入

9.简述ascii、Unicode、utf-8的关系

答:

American Standard Code for Information Interchange

是存储了欧美国家在计算机中可以用到字符和对应二进制的字符集,这些二进制使用8位表示足够

Unicode:描述全球人使用字符和对应码位的字符集 使用32位表示码位范围。

utf-8是对unicode的码位进行画区间然后根据字符的码位区间进行模板选择完成Unicode码位和模板的填充

10.判断Go语言中的字符是utf-8编码的字节

name:="张根"

fmt.Println(strconv.FormatInt(int64(name[0]),2))

fmt.Println(strconv.FormatInt(int64(name[1]),2))

fmt.Println(strconv.FormatInt(int64(name[2]),2))

//11100101 10111100 10100000 去对应utf-8的模板一看便知

11.什么是rune?

rune表示英文字符或者汉字在Unicode字符中对应的码位

name:="张根"

EnglishName:="Martin"

fmt.Println([]rune(name))

fmt.Println([]rune(EnglishName))

[24352 26681]

[77 97 114 116 105 110]

12.判断:字符串是否可变?

答:不可变

13.列举你记得的字符串常见功能

答:Prefix() stufix()

14.字符串集合和rune集合如何实现相互转换

name:="Alex"

newRune:=[]rune(name)

newRune[0]='a'

fmt.Println(string(newRune))

15.如何实现字符串高效率拼接

var builder strings.Builder

builder.WriteString("我爱")

builder.WriteString("北")

builder.WriteString("京")

result11:=builder.String()

fmt.Println(result11)

16.简述数组的存储原理

答:一块连续的内存地址,第一个元素即该数组的内存地址。如果数组内包含字符串 存储字符串(长度+指针)进行统一规格!

17.names:=[3]string{"alex","超级无敌小JJ","傻儿子"}

a.根据索引获取“傻儿子”

b.根据索引获取“alex”

c.根据索引获取“小JJ”

d.请将names数组最后1个元素修改为“大烧瓶”

答:

names := [3]string{"alex", "超级无敌小JJ", "傻儿子"}

fmt.Println(names[0])

fmt.Println(names[1])

fmt.Println(names[2])

names[0]="大烧饼"

fmt.Println(names)

18.看代码输出结果

var nestdata [3][2]int

fmt.Println(nestdata)

[[0 0] [0 0] [0 0]]

19.请声明1个3个元素的数组,元素的类型是数组,并在数组中初始化值

var nestdata=[3][2]int{{1,2},{3,4},{5,6}}

fmt.Println(nestdata)

20循环下列数组并使用字符串格式化输出一下内容:

dataList:=[

["alex","qwe123"],

["eric","qw2"],

["tony","qpep23"],

]

最终实现:

我是Alex我的密码是qwe123

答:

var userList = [3][2]string{{"alex", "qwe123"}, {"eric", "qw2"}, {"tony", "qpep23"}}

fmt.Println(userList)

for _, item := range userList {

fmt.Printf("我是%s我的秘密是%s\n", item[0], item[1])

}

21.实现用户登录

//userList中有3个用户,

dataList:=[

["alex","qwe123"],

["eric","qw2"],

["tony","qpep23"],

]

从dataList中获取用户名验证用户合法性*/func main() {var userList = [3][2]string{{"alex", "qwe123"}, {"eric", "qw2"}, {"tony", "qpep23"}}var userName string

var passWord stringfmt.Print("请输入用户名:")

fmt.Scan(&userName)

fmt.Print("请输入秘密:")

fmt.Scan(&passWord)

isAuthenticated := 0

if len(userName) > 0 && len(passWord) > 0{

isAuthenticated= 197

for _, item :=range userList {if userName == item[0] {//当用户名和密码全部正确是也会走这个if分支!

isAuthenticated = 198}if passWord == item[1] {//当用户名和密码全部正确是也会走 这个if分支!

isAuthenticated = 199}if userName == item[0] && passWord == item[1] {

isAuthenticated= 200

break}

}

}switchisAuthenticated {case 200:

fmt.Println("登录成功!")case 197:

fmt.Println("用户和密码都不对!")case 198:

fmt.Println("用户对了,密码不对!")case 199:

fmt.Println("密码对了,用户名不对!")default:

fmt.Println("用户和密码都没有输入!")

}

}

Doing more practice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值