PHP转Go之数组的正确使用详解

 更新时间:2023年09月17日 11:38:06   作者:全Neng攻城狮  
这篇文章主要为大家对比一下PHP中的Array和Golang中的 Array&Slice&Map,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

本文概要

思维速转,PHP Array -> Go Array or Slice or Map

底层实现的异同

使用中的注意事项及坑坑

  • 如何选择 Array 和 Slice
  • 值传递和引用传递的坑
  • Map 的无序
  • 并发安全性

一、思维速转

PHP 中 Array 实在是太好用了,即可以声明为索引数组,又可以声明为关联数组;但是在 Golang 中,被拆解成了多个数据类型,其中索引数组与 Array/Slice 更贴近,而关联数组更贴近于 Map

// 索引数组
$colors = array("red", "green", "blue");  
// Go Array: [3]string{"red", "green", "blue"} // 固定长度
// Go Slice: []string{"red", "green", "blue"}
// 关联数组
$person = array(
    "first_name" => "John",
    "last_name" => "Doe",
    "age" => 30
);
// 对比 Golang Map
person := map[string]string{
    "first_name": "John",
    "last_name": "Doe",
    "age": "30",   // 特别注意强类型下 map 中值部分无法存放不同类型的数据
}

二、底层实现的异同

PHP 的语法上屏蔽了索引数组和关联数组,底层实现均基于 HashTable 完成,但是对于 Golang 来说,不同的类型实现是略有差异的;

Array 底层实现

Go 的 Array 一定是预先确定长度的,故底层分配的是固定连续内存,变量在声明后,直接指向数组存储的内存地址,所以读取会非常高效

arr := [3]int32{1,2,3}
fmt.Println(&arr[0],&arr[1],&arr[2])
// Output: 可以看到每个元素偏移刚好是 4 个字节
0xc0000a6030 0xc0000a6034 0xc0000a6038

特别注意,对于[3]string 字符串数组来说,string 实际上是存放在独立的内存中的,所以数组中保存的是字符串地址,所以打印出来的地址偏移是 16 个字节(string 底层数据结构包括一个指向字符串真实地址的指针,以及一个字符串长度的值)

注意,所有这些字节偏移均是 64 位机器上

Slice 底层实现

Slice 实际上底层也是引用了数组的实现,但是它在数组的上面又封装了一层数据结构,当我们打印 Slice 中每个元素的内存地址时你会发现其每个元素的偏移规则与数组是一致的。差别在于当我们打印整个数组的指针地址时会发现其与数组第一个元素的地址是一致的,而 Slice 的不同。

type slice struct {
    array unsafe.Pointer  // 指向底层数组
    len   int
    cap   int
}
arr := [3]int64{1,2,3}
fmt.Printf("arr : %p \n", &arr)
fmt.Println(&arr,&arr[0],&arr[1],&arr[2])
slice := []int64{1,2,3}
fmt.Printf("slice : %p \n", &slice)
fmt.Println(&slice,&slice[0],&slice[1],&slice[2])
// Output:
arr : 0xc000018120 // 与第一个元素一致
&[1 2 3] 0xc000018120 0xc000018128 0xc000018130
slice : 0xc000010078 // 指向 Slice 结构体指针,故与第一个元素内存不一致
&[1 2 3] 0xc000018150 0xc000018158 0xc000018160

Slice 实际上实现了高效的动态扩容能力,故对比 Array 来说应用场景更广泛

Map 底层实现

Golang 的 Map 底层实现也同样是 HashTable ,相同点是,查找插入效率高,支持动态扩容等,但是 Golang 下的 Map 在遍历时是无序的,php 下的关联数组则是有序的;

关于 Golang 中 Array,Slice,Map 更详细的底层实现有大量文章分析,这里不再赘述

使用中的注意事项及坑坑

Array 和 Slice 的选择

Array 在某些场景下的确是使用起来会更高效,所以原则上在某些特别注意性能,且的确是不需要数据长度变动的情况下可以选择 Array,但是,我要特别说明,这种场景极少极少,在日常业务系统开发中,无脑选择使用 Slice 通常是正确的选择

值传递和引用传递

Array 是值传递,Slice 和 Map 是引用传递,换句话说,Array 将数据传递到子函数后在子函数做任何修改,不会影响父函数内原始数据,但是 Slice 和 Map 不一样,子函数对数据的修改会修改原始数据,所以在上面无脑选择 Slice 时要特别注意这一项,是否担心子函数意外修改数据

Map 的无序的坑

这个从 PHP 转到 Go 可能无法注意到的一点,每次循环 Map 居然可能会得到完全不一样的顺序的结果,所以要想保证 Map 顺序通常需要配合 slice 完成,或者借助第三方库,比如:https://github.com/iancoleman/orderedmaphttps://github.com/wangjia184/sortedset 但实际上这种可能也会带来 json 序列化的坑,所以从接口设计上就应尽可能避免,对有序要求的尽可能使用 Slice

并发安全性

Go 是一个语言级别就支持并发的语言,但是 Slice 和 Map 都是并发不安全的类型,所以在并发操作 Slice 和 Map 时可能会引起冲突,故要特别注意,修改数据时需要引入 sync.Mutex 互斥锁 or 利用 channel 完成,Map 还提供了一个并发安全的类型 sync.Map 来解决这个问题。

强类型下 Golang Array灵活性降低

接受它!

当你接触了 Golang 下数组们的实现,会发现它真的没有 php 下的数组灵活好用,这其实是强类型语言的通病,虽然 Golang 也可以通过定义 []interface{} 类型的 Slice,但是强烈不建议这样用,强类型的优点是让我们尽可能早的发现问题,比如在编码时 IDE 就能做到提示,而非在运行

到此这篇关于PHP转Go之数组的正确使用详解的文章就介绍到这了,更多相关PHP转Go内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 探讨各种PHP字符串函数的总结分析

    探讨各种PHP字符串函数的总结分析

    本篇文章是对各种PHP字符串函数进行了详细的总结与分析,需要的朋友参考下
    2013-06-06
  • PHP生成和获取XML格式数据的方法

    PHP生成和获取XML格式数据的方法

    这篇文章主要介绍了PHP生成和获取XML格式数据的方法,结合实例形式较为详细的分析了PHP操作数据库生成XML及获取XML格式数据的相关技巧,需要的朋友可以参考下
    2016-03-03
  • php 批量替换html标签的实例代码

    php 批量替换html标签的实例代码

    这篇文章主要是对php批量替换html标签的实例代码进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-11-11
  • PHP浮点数精度问题汇总

    PHP浮点数精度问题汇总

    这篇文章主要介绍了PHP浮点数精度问题汇总,本文着重探讨PHP浮点数精度损失问题,用三个段落不同的方式讲解了这个问题的形成原因以及解决方法,需要的朋友可以参考下
    2015-05-05
  • PHP 99乘法表的几种实现代码

    PHP 99乘法表的几种实现代码

    对于刚学PHP的新手来讲,用php写九九乘法表无疑是非常经典的一道练习题,但不要小看这道练习题,它对于逻辑的考验还是相当到位的,这里脚本之家小编就为大家分享一下
    2020-10-10
  • PHP获取二叉树镜像的方法

    PHP获取二叉树镜像的方法

    这篇文章主要介绍了PHP获取二叉树镜像的方法,涉及php使用队列针对二叉树进行翻转的相关操作技巧,需要的朋友可以参考下
    2018-01-01
  • php 利用socket发送HTTP请求(GET,POST)

    php 利用socket发送HTTP请求(GET,POST)

    作为php程序员一定会接触http协议,也只有深入了解http协议,编程水平才会更进一步。最近我一直在学习php的关于http的编程,许多东西恍然大悟,受益匪浅。希望分享给大家。本文需要有一定http基础的开发者阅读。
    2015-08-08
  • php实现购物车功能(以大苹果购物网为例)

    php实现购物车功能(以大苹果购物网为例)

    本文主要介绍了php实现购物车功能(以大苹果购物网为例)的实现方法,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • php获取通过http协议post提交过来xml数据及解析xml

    php获取通过http协议post提交过来xml数据及解析xml

    php 如何获取请求的xml数据,对方通过http协议post提交过来xml数据,php如何获取到这些数据呢?
    2012-12-12
  • PHP基于单例模式实现的数据库操作基类

    PHP基于单例模式实现的数据库操作基类

    这篇文章主要介绍了PHP基于单例模式实现的数据库操作基类,涉及PHP操作数据库的基本配置与增删改查等操作技巧,需要的朋友可以参考下
    2016-01-01

最新评论