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

yvsm5个月前Go语言8090

作为PHP开发者,你熟悉用class定义类、interface定义接口,通过实例化对象实现面向对象编程。Go没有“类(class)”的概念,但通过结构体(struct)实现类的属性封装,通过方法(method)实现类的行为,通过接口(interface)实现多态——核心逻辑与PHP面向对象一致,但语法更简洁、无继承(用组合替代)。今天我们就以PHP的类/接口为参照,快速掌握Go面向对象编程的核心。

一、Go结构体(struct):对标PHP的类

Go结构体是“不同类型字段的集合”,对标PHP类的“属性集合”,是Go实现数据封装的核心,替代PHP的class定义。

1. 结构体声明与初始化(对标PHP类的定义与实例化)

特性Go结构体PHP类
声明关键字type 结构体名 structclass 类名
属性定义字段名+类型(如Name string属性(可加访问修饰符,如public $name
实例化字面量/new关键字new 类名()/类名::new()

基础示例:Go结构体 vs PHP类

// Go结构体定义(用户结构体)
type User struct {
    // 字段名首字母大写=公开(对标PHP public),小写=私有(仅当前包可见)
    Name string
    Age  int
    Score float64
}

// 结构体实例化与使用
func main() {
    // 方式1:字面量初始化(对标PHP $user = new User(); $user->name = "张三")
    u1 := User{
        Name:  "张三",
        Age:   25,
        Score: 90.5,
    }
    fmt.Println(u1.Name) // 输出张三

    // 方式2:new关键字(返回指针)
    u2 := new(User)
    u2.Name = "李四"
    u2.Age = 30
    fmt.Println(u2.Age) // 输出30

    // 方式3:部分字段初始化(未初始化的字段为默认值)
    u3 := User{Name: "王五"}
    fmt.Println(u3.Age) // 输出0(int默认值)
}

PHP对应写法(无

// PHP类定义
class User {
    // 公开属性(对标Go首字母大写字段)
    public $name;
    public $age;
    public $score;
}

// 实例化与使用
$u1 = new User();
$u1->name = "张三";
$u1->age = 25;
$u1->score = 90.5;
echo $u1->name . "\n"; // 输出张三

$u2 = new User();
$u2->name = "李四";
$u2->age = 30;
echo $u2->age . "\n"; // 输出30

$u3 = new User();
$u3->name = "王五";
echo $u3->age . "\n"; // 输出null(PHP默认值)

⚠️ 核心差异:
       1. Go无访问修饰符(public/private),通过字段名首字母大小写控制可见性(大写=公开,小写=私有);PHP通过public/private/protected控制;
       2. Go结构体实例化的未初始化字段为类型默认值(int=0、string="");PHP类属性未初始化则为null;
       3. Go无“构造函数”,但可通过自定义函数模拟(如下文)。

2. 结构体方法(对标PHP类的方法)

Go可给结构体绑定“方法”,对标PHP类的成员方法,语法:func (接收者 结构体类型) 方法名(参数) 返回值 {}

基础示例:绑定方法到结构体

// Go结构体方法
type User struct {
    Name string
    Age  int
}

// 绑定方法到User(值接收者:复制结构体,对标PHP值传递)
func (u User) SayHello() {
    fmt.Printf("你好,我是%s,今年%d岁\n", u.Name, u.Age)
}

// 指针接收者:修改原结构体,对标PHP传引用
func (u *User) GrowUp() {
    u.Age += 1 // 修改原结构体的Age字段
}

func main() {
    u := User{Name: "张三", Age: 25}
    u.SayHello() // 输出:你好,我是张三,今年25岁
    u.GrowUp()
    fmt.Println(u.Age) // 输出26
}

PHP对应写法:

// PHP类方法
class User {
    public $name;
    public $age;

    // 成员方法
    public function sayHello() {
        echo "你好,我是{$this->name},今年{$this->age}岁\n";
    }

    // 修改属性的方法
    public function growUp() {
        $this->age += 1;
    }
}

$u = new User();
$u->name = "张三";
$u->age = 25;
$u->sayHello(); // 输出:你好,我是张三,今年25岁
$u->growUp();
echo $u->age . "\n"; // 输出26

💡 核心知识点:
       1. Go方法的“接收者”对标PHP的$this,用于关联结构体;
       2. 值接收者:方法内修改的是结构体副本,不影响原对象;指针接收者:修改原对象,开发中更常用;
       3. Go无“静态方法”,但可通过“包级函数”或“绑定到结构体指针”模拟。

3. 模拟构造函数(对标PHP __construct)

Go无内置构造函数,但可自定义函数返回结构体实例,对标PHP的__construct

// Go自定义构造函数(NewUser为约定俗成的构造函数名)
func NewUser(name string, age int) *User {
    // 可添加参数校验逻辑
    if age < 0 {
        age = 0
    }
    return &User{
        Name: name,
        Age:  age,
    }
}

func main() {
    // 调用构造函数实例化
    u := NewUser("张三", -5) // 年龄为负,自动修正为0
    fmt.Println(u.Age) // 输出0
}

PHP对应写法:

// PHP构造函数
class User {
    public $name;
    public $age;

    // 构造函数
    public function __construct($name, $age) {
        $this->name = $name;
        if ($age < 0) {
            $this->age = 0;
        } else {
            $this->age = $age;
        }
    }
}

// 实例化(自动调用构造函数)
$u = new User("张三", -5);
echo $u->age . "\n"; // 输出0

二、Go接口(interface):对标PHP的接口

Go接口是“方法签名的集合”,对标PHP接口的“方法声明集合”,但Go接口无需显式实现(只要结构体有接口的所有方法,就自动实现该接口)——这是Go的“鸭子类型”(长得像鸭子就是鸭子)。

1. 接口声明与实现(对标PHP interface/implements)

// Go接口声明(定义Speak方法签名)
type Speaker interface {
    Speak() string // 声明方法:无参数,返回string
}

// 定义Cat结构体
type Cat struct {
    Name string
}

// Cat实现Speak方法(自动实现Speaker接口,无需显式声明)
func (c Cat) Speak() string {
    return c.Name + ":喵喵喵"
}

// 定义Dog结构体
type Dog struct {
    Name string
}

// Dog实现Speak方法(也自动实现Speaker接口)
func (d Dog) Speak() string {
    return d.Name + ":汪汪汪"
}

// 接收Speaker接口的函数(多态:可传入任意实现该接口的结构体)
func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    cat := Cat{Name: "小花"}
    dog := Dog{Name: "大黄"}
    MakeSound(cat) // 输出:小花:喵喵喵
    MakeSound(dog) // 输出:大黄:汪汪汪
}

PHP对应写法(需显式implements):

// PHP接口声明
interface Speaker {
    public function speak(): string;
}

// Cat类实现Speaker接口(需显式声明implements)
class Cat implements Speaker {
    public $name;

    public function __construct($name) {
        $this->name = $name;
    }

    // 实现接口的speak方法
    public function speak(): string {
        return $this->name . ":喵喵喵";
    }
}

// Dog类实现Speaker接口
class Dog implements Speaker {
    public $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function speak(): string {
        return $this->name . ":汪汪汪";
    }
}

// 接收Speaker接口的函数
function makeSound(Speaker $s) {
    echo $s->speak() . "\n";
}

// 调用
$cat = new Cat("小花");
$dog = new Dog("大黄");
makeSound($cat); // 输出:小花:喵喵喵
makeSound($dog); // 输出:大黄:汪汪汪

⚠️ 核心差异:
       1. Go接口无需显式实现(无implements关键字),PHP必须显式声明implements
       2. Go接口是“非侵入式”的(接口定义不依赖实现者),PHP接口是“侵入式”的;
       3. Go接口仅声明方法签名,无属性;PHP接口也无属性,仅声明方法。

2. 空接口(interface{}):对标PHP的任意类型

Go的空接口interface{}没有任何方法签名,可接收任意类型的值,对标PHP的“无类型约束”(如函数参数不指定类型):

// Go空接口:接收任意类型
func PrintAnything(v interface{}) {
    fmt.Printf("类型:%T,值:%v\n", v, v)
}

func main() {
    PrintAnything(100)        // 输出:类型:int,值:100
    PrintAnything("Go语言")    // 输出:类型:string,值:Go语言
    PrintAnything(User{Name: "张三"}) // 输出:类型:main.User,值:{张三 0}
}

PHP对应写法:

// PHP无类型约束的函数
function printAnything($v) {
    echo "类型:" . gettype($v) . ",值:" . var_export($v, true) . "\n";
}

printAnything(100); // 输出:类型:integer,值:100
printAnything("Go语言"); // 输出:类型:string,值:'Go语言'
$user = new User();
$user->name = "张三";
printAnything($user); // 输出:类型:object,值:User::__set_state(array(...))

三、实战案例:PHP vs Go 面向对象实现计算器

需求:定义计算器结构体/类,实现加法、减法方法

Go写法(结构体+方法)

package main

import "fmt"

// 计算器结构体
type Calculator struct {
    Num1 float64
    Num2 float64
}

// 构造函数
func NewCalculator(num1, num2 float64) *Calculator {
    return &Calculator{Num1: num1, Num2: num2}
}

// 加法方法
func (c *Calculator) Add() float64 {
    return c.Num1 + c.Num2
}

// 减法方法
func (c *Calculator) Sub() float64 {
    return c.Num1 - c.Num2
}

func main() {
    calc := NewCalculator(10.5, 5.2)
    fmt.Printf("加法结果:%.2f\n", calc.Add()) // 输出:加法结果:15.70
    fmt.Printf("减法结果:%.2f\n", calc.Sub()) // 输出:减法结果:5.30
}

PHP写法(类+方法)

// 计算器类
class Calculator {
    public $num1;
    public $num2;

    // 构造函数
    public function __construct($num1, $num2) {
        $this->num1 = $num1;
        $this->num2 = $num2;
    }

    // 加法方法
    public function add(): float {
        return $this->num1 + $this->num2;
    }

    // 减法方法
    public function sub(): float {
        return $this->num1 - $this->num2;
    }
}

// 使用
$calc = new Calculator(10.5, 5.2);
echo "加法结果:" . number_format($calc->add(), 2) . "\n"; // 输出:加法结果:15.70
echo "减法结果:" . number_format($calc->sub(), 2) . "\n"; // 输出:减法结果:5.30

五、今日小结

今天我们以PHP类/接口为参照,掌握了Go面向对象的核心:

  1. Go结构体(struct)对标PHP类,通过字段封装数据,字段名大小写控制可见性;

  2. Go方法通过“接收者”绑定到结构体,对标PHP的成员方法,指针接收者可修改原结构体;

  3. Go接口是方法签名集合,无需显式实现(鸭子类型),对标PHP接口但更灵活;

  4. Go无继承,通过“结构体嵌套”(组合)替代PHP的类继承,空接口interface{}可接收任意类型。

明天我们将学习Go的错误处理与文件操作(对标PHP的异常处理/文件函数),详解Go如何处理错误、读写文件,继续用PHP思维快速上手Go的实用功能。

标签: PHP转Go

相关文章

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

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

第一天:从PHP到Golang,零基础入门的环境搭建与第一个程序

作为一名PHP开发者,当你决定接触Golang(简称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的变量/数据类型为参照,快速掌握Go的变量声...

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

作为PHP开发者,你早已习惯了“万能数组”——既可以当索引数组用,也可以当关联数组用,长度动态变化、元素类型不限。而Go没有“万能数组”,而是将复合数据类型拆分为数组(array)、切...

发表评论    

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