第六天:PHP开发者快速掌握Go结构体与接口 | 从PHP类/接口到Go面向对象
作为PHP开发者,你熟悉用class定义类、interface定义接口,通过实例化对象实现面向对象编程。Go没有“类(class)”的概念,但通过结构体(struct)实现类的属性封装,通过方法(method)实现类的行为,通过接口(interface)实现多态——核心逻辑与PHP面向对象一致,但语法更简洁、无继承(用组合替代)。今天我们就以PHP的类/接口为参照,快速掌握Go面向对象编程的核心。
一、Go结构体(struct):对标PHP的类
Go结构体是“不同类型字段的集合”,对标PHP类的“属性集合”,是Go实现数据封装的核心,替代PHP的class定义。
1. 结构体声明与初始化(对标PHP类的定义与实例化)
| 特性 | Go结构体 | PHP类 |
|---|---|---|
| 声明关键字 | type 结构体名 struct | class 类名 |
| 属性定义 | 字段名+类型(如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面向对象的核心:
Go结构体(struct)对标PHP类,通过字段封装数据,字段名大小写控制可见性;
Go方法通过“接收者”绑定到结构体,对标PHP的成员方法,指针接收者可修改原结构体;
Go接口是方法签名集合,无需显式实现(鸭子类型),对标PHP接口但更灵活;
Go无继承,通过“结构体嵌套”(组合)替代PHP的类继承,空接口
interface{}可接收任意类型。
明天我们将学习Go的错误处理与文件操作(对标PHP的异常处理/文件函数),详解Go如何处理错误、读写文件,继续用PHP思维快速上手Go的实用功能。
