第五天:PHP开发者快速掌握Go数组、切片与Map | 从PHP数组到Go复合类型的转换

yvsm5个月前Go语言6360

作为PHP开发者,你早已习惯了“万能数组”——既可以当索引数组用,也可以当关联数组用,长度动态变化、元素类型不限。而Go没有“万能数组”,而是将复合数据类型拆分为数组(array)切片(slice)映射(map):数组对应PHP固定长度索引数组,切片对应PHP动态索引数组,Map对应PHP关联数组。今天我们就以PHP数组为参照,快速掌握Go这三种核心复合类型的声明、操作和核心差异。

一、Go数组(对标PHP固定长度索引数组)

Go数组是“长度固定、元素类型统一”的有序集合,对标PHP中手动限制长度的索引数组(如array_fill(0, 3, '')),但Go的长度是编译期常量,无法动态修改。

1. 数组声明与初始化

声明方式 Go代码示例 PHP等效代码
指定长度+类型 var arr [3]int(长度3,int类型,默认值0) $arr = array_fill(0, 3, 0);
声明并初始化 var arr [3]int = [3]int{10, 20, 30} $arr = [10, 20, 30];
长度推导(...) arr := [...]int{10, 20, 30}(自动推导长度3) $arr = [10, 20, 30];(PHP自动推导长度)

基础操作示例:Go数组 vs PHP索引数组

// Go数组操作
func main() {
    // 声明并初始化数组
    arr := [3]int{10, 20, 30}
    // 访问元素(下标从0开始,对标PHP)
    fmt.Println(arr[0]) // 输出10
    // 修改元素(仅能修改已有下标,不能新增)
    arr[1] = 200
    fmt.Println(arr) // 输出[10 200 30]
    // 获取长度(len函数,对标PHP count())
    fmt.Println(len(arr)) // 输出3

    // 错误:数组长度固定,无法新增元素
    // arr[3] = 400 // 编译报错:index 3 out of range [0:3]
}

PHP对应写法:

// PHP索引数组操作
$arr = [10, 20, 30];
echo $arr[0] . "\n"; // 输出10
$arr[1] = 200;
print_r($arr); // 输出Array ( [0] => 10 [1] => 200 [2] => 30 )
echo count($arr) . "\n"; // 输出3

// PHP可新增元素(动态长度)
$arr[3] = 400;
print_r($arr); // 输出Array ( [0] => 10 [1] => 200 [2] => 30 [3] => 400 )

⚠️ 核心差异:
       1. Go数组长度固定,编译期确定,无法新增/删除元素;PHP索引数组长度动态,可随意增删;
       2. Go数组元素类型必须统一(如全int);PHP数组可混合类型(如[int, string, bool]);
       3. Go数组是值类型(赋值/传参时复制整个数组);PHP数组是引用类型(赋值默认浅拷贝)。

二、Go切片(slice):对标PHP动态索引数组

Go数组的“长度固定”特性限制了灵活性,因此实际开发中几乎不用数组,而是用切片(slice)——切片是数组的“动态视图”,长度可动态扩容,完全对标PHP的动态索引数组,是Go中最常用的集合类型。

1. 切片声明与初始化

切片无固定长度,声明时无需指定长度,核心初始化方式如下:

初始化方式 Go代码示例 PHP等效代码
空切片 var s []int(长度0,容量0) $s = [];
字面量初始化 s := []int{10, 20, 30} $s = [10, 20, 30];
基于数组创建 arr := [3]int{10,20,30}; s := arr[0:2](取数组0-1下标) $arr = [10,20,30]; $s = array_slice($arr, 0, 2);
make创建(指定容量) s := make([]int, 2, 5)(长度2,容量5) $s = array_fill(0, 2, 0);(PHP无“容量”概念)

2. 切片核心操作(对标PHP数组操作)

(1)新增元素:append(对标PHP $arr[] = 值)

// Go切片新增元素(append)
func main() {
    s := []int{10, 20}
    // 追加单个元素(对标PHP $s[] = 30)
    s = append(s, 30)
    // 追加多个元素(对标PHP array_push($s, 40, 50))
    s = append(s, 40, 50)
    fmt.Println(s) // 输出[10 20 30 40 50]
}

PHP对应写法:

// PHP新增数组元素
$s = [10, 20];
$s[] = 30;
array_push($s, 40, 50);
print_r($s); // 输出Array ( [0] => 10 [1] => 20 [2] => 30 [3] => 40 [4] => 50 )

(2)切片截取:s[start:end](对标PHP array_slice)

// Go切片截取
func main() {
    s := []int{10,20,30,40,50}
    // 取下标1到3(含1,不含3)
    sub := s[1:3]
    fmt.Println(sub) // 输出[20 30]
    // 省略start:从0开始
    sub1 := s[:2] // [10,20]
    // 省略end:到最后
    sub2 := s[3:] // [40,50]
}

PHP对应写法:

// PHP array_slice截取
$s = [10,20,30,40,50];
$sub = array_slice($s, 1, 2); // 从下标1取2个
print_r($sub); // 输出Array ( [0] => 20 [1] => 30 )
$sub1 = array_slice($s, 0, 2); // [10,20]
$sub2 = array_slice($s, 3); // [40,50]

(3)删除元素:append组合截取(对标PHP unset)

// Go切片删除元素(删除下标2的元素)
func main() {
    s := []int{10,20,30,40,50}
    // 拼接:前2个元素 + 从3开始的元素
    s = append(s[:2], s[3:]...)
    fmt.Println(s) // 输出[10 20 40 50]
}

PHP对应写法:

// PHP删除数组元素
$s = [10,20,30,40,50];
unset($s[2]);
// 重置下标(可选,Go切片无此问题)
$s = array_values($s);
print_r($s); // 输出Array ( [0] => 10 [1] => 20 [2] => 40 [3] => 50 )

💡 核心知识点:
       1. 切片是引用类型(底层指向数组),赋值/传参时仅复制引用,不复制数据;
       2. 切片有“长度(len)”和“容量(cap)”:长度是当前元素个数,容量是底层数组的可用长度,扩容时会自动分配更大的底层数组。

三、Go Map(对标PHP关联数组)

Go Map是“键值对”集合,完全对标PHP的关联数组,但Go的键/值类型必须统一(如键为string、值为int),且键必须是“可比较类型”(如string、int,不能是切片/Map)。

1. Map声明与初始化

初始化方式 Go代码示例 PHP等效代码
空Map var m map[string]int(需make初始化才能使用) $m = [];
make创建 m := make(map[string]int, 5)(容量5,可选) $m = [];(PHP无容量概念)
字面量初始化 m := map[string]int{"age":30, "score":95} $m = ["age"=>30, "score"=>95];

2. Map核心操作(对标PHP关联数组)

// Go Map CRUD操作
func main() {
    // 初始化Map
    user := make(map[string]interface{}) // 值为interface{}可存任意类型(类似PHP混合类型)
    // 新增/修改元素(对标PHP $user["name"] = "张三")
    user["name"] = "张三"
    user["age"] = 30
    user["score"] = 95.5

    // 访问元素(对标PHP $user["name"])
    fmt.Println(user["name"]) // 输出张三

    // 判断键是否存在(Go独有,对标PHP isset($user["gender"]))
    gender, ok := user["gender"]
    if !ok {
        fmt.Println("gender键不存在") // 输出此内容
        user["gender"] = "男" // 新增键
    }

    // 删除元素(delete函数,对标PHP unset($user["score"]))
    delete(user, "score")
    fmt.Println(user) // 输出map[age:30 gender:男 name:张三]

    // 遍历Map(对标PHP foreach)
    for k, v := range user {
        fmt.Printf("键:%s,值:%v\n", k, v)
    }
}

PHP对应写法:

// PHP关联数组CRUD操作
$user = [];
// 新增/修改
$user["name"] = "张三";
$user["age"] = 30;
$user["score"] = 95.5;

// 访问
echo $user["name"] . "\n"; // 输出张三

// 判断键是否存在
if (!isset($user["gender"])) {
    echo "gender键不存在\n";
    $user["gender"] = "男";
}

// 删除
unset($user["score"]);
print_r($user); // 输出Array ( [name] => 张三 [age] => 30 [gender] => 男 )

// 遍历
foreach ($user as $k => $v) {
    echo "键:{$k},值:{$v}\n";
}

⚠️ 核心差异:
       1. Go Map的键类型必须统一且可比较(如全string);PHP关联数组键可混合int/string;
       2. Go访问不存在的键返回值类型的默认值(如int返回0),需用ok判断是否存在;PHP访问不存在的键返回null;
       3. Go Map遍历顺序不固定(每次遍历可能不同);PHP关联数组遍历顺序与插入顺序一致(PHP7+)。

四、实战案例:PHP vs Go 处理用户列表数据

需求:定义用户列表,筛选出年龄≥18的用户,输出用户名和年龄

Go写法(切片+Map)

package main

import "fmt"

func main() {
    // 用户列表(切片嵌套Map)
    users := []map[string]interface{}{
        {"name": "张三", "age": 25},
        {"name": "李四", "age": 17},
        {"name": "王五", "age": 30},
    }

    // 筛选成年用户
    adultUsers := []map[string]interface{}{}
    for _, user := range users {
        age := user["age"].(int) // 类型断言(对标PHP类型转换)
        if age >= 18 {
            adultUsers = append(adultUsers, user)
        }
    }

    // 输出结果
    fmt.Println("成年用户:")
    for _, u := range adultUsers {
        fmt.Printf("姓名:%s,年龄:%d\n", u["name"], u["age"])
    }
}

PHP写法(关联数组嵌套)

// 用户列表(关联数组嵌套)
$users = [
    ["name" => "张三", "age" => 25],
    ["name" => "李四", "age" => 17],
    ["name" => "王五", "age" => 30],
];

// 筛选成年用户
$adultUsers = [];
foreach ($users as $user) {
    if ($user["age"] >= 18) {
        $adultUsers[] = $user;
    }
}

// 输出结果
echo "成年用户:\n";
foreach ($adultUsers as $u) {
    echo "姓名:{$u['name']},年龄:{$u['age']}\n";
}

五、今日小结

今天我们以PHP数组为参照,掌握了Go的三大复合数据类型:

  1. Go数组长度固定、值类型,实际开发中极少使用,对标PHP固定长度索引数组;

  2. Go切片是动态数组、引用类型,核心操作append/截取/删除,完全对标PHP动态索引数组,是Go最常用的集合类型;

  3. Go Map是键值对集合,类型约束更严格,需用ok判断键是否存在,对标PHP关联数组;

  4. Go无“万能数组”,需根据场景选择切片/Map,类型安全性远高于PHP数组。

明天我们将学习Go的结构体与接口(对标PHP的类/接口),详解Go面向对象编程的核心逻辑,继续用PHP思维快速上手Go的面向对象特性。

标签: PHP转Go

相关文章

第七天:PHP开发者快速掌握Go错误处理与文件操作 | 从PHP异常/文件函数到Go实战

作为PHP开发者,你熟悉用try/catch处理异常、file_get_contents/file_put_contents读写文件、mkdir创建目录。Go没有“异常(Exception)”的概念,...

第八天:PHP开发者快速掌握Go并发编程 | Goroutine与Channel从入门到实战

作为PHP开发者,你知道实现并发需要依赖pcntl扩展创建多进程、pthreads扩展实现多线程,或借助Swoole/Workerman框架——步骤繁琐且资源消耗高。而Go内置原生并发支持:Gorou...

第六天:PHP开发者快速掌握Go结构体与接口 | 从PHP类/接口到Go面向对象

作为PHP开发者,你熟悉用class定义类、interface定义接口,通过实例化对象实现面向对象编程。Go没有“类(class)”的概念,但通过结构体(struct)实现类的属性封装,通过方法(me...

第三天:PHP 开发者快速掌握 Go 运算符与流程控制

作为PHP开发者,你早已熟悉if/else、for、foreach等流程控制语法,以及+/-/*/、==/===等运算符。Go的运算符和流程控制语法与PHP高度相似,但也有不少“细节差异”——比如Go...

第四天:PHP 开发者快速掌握 Go 函数

作为PHP开发者,你早已熟悉function定义函数、参数传值/传引用、return返回结果的逻辑。Go的函数体系更严谨、功能更丰富——支持多返回值、命名返回值、可变参数,且函数本身可作为参数/返回值...

第二天:PHP 开发者快速掌握 Go 变量与数据类型

作为PHP开发者,你早已习惯了“无需声明类型、变量随用随定义”的弱类型特性,而Go作为强类型语言,变量必须显式声明类型(或通过推导确定)。今天我们就以PHP的变量/数据类型为参照,快速掌握Go的变量声...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。