对象模型与内存的“钥匙理论”:TS 切入的 Go 的结构体与指针

🚀 省流助手(速通结论)

  • Struct 不是类:它只存数据,不存逻辑。逻辑通过"接收者(Receiver)"外挂实现,类似 JS 的 prototype
  • 没有 this:Go 显式命名接收者(如 u),彻底解决了 TS 中 this 指向丢失的世纪难题。
  • 权限全靠"吼":首字母大写 = public,首字母小写 = private。这是编译器级别的强制隔离。
  • 赋值即复印:a := b 是物理深拷贝。想要引用?必须显式使用 & 拿钥匙(指针)。
  • 契约严苛:函数要求指针(*User)时,你传值(User)会直接编译报错,Go 不玩隐式转换。

1. 结构体不是类:数据与逻辑的彻底解耦

在 TS 中,class 是高度内聚的。但在 Go 中,struct 被剥离得只剩下数据描述。

TypeScript(内聚模型)

typescript 复制代码
class User {
    name: string;
    constructor(name: string) { this.name = name; }
    say() { console.log(this.name); } // 逻辑住在类里面
}

Go(数据模型)

go 复制代码
type User struct {
    Name string // 仅定义数据字段
}

// 逻辑通过外部函数"外挂"到 User 上
func (u User) Say() {
    fmt.Println(u.Name)
}

🪝 思维钩子:Go 强迫你把"长什么样"和"能干什么"分开。你可以把 struct 看作是去掉了方法实现的"瘦身版" Class。


2. 方法的外挂艺术:再见了,迷之 this

TS 开发者最头疼的莫过于 this 绑定丢失。Go 根本不设 this 关键字,而是让你显式命名。

TypeScript(this 绑定焦虑)

ini 复制代码
const u = new User("Alice");
const say = u.say;
say(); // ❌ 报错:this 指向丢失(除非 bind 或用箭头函数)

Go(显式绑定)

scss 复制代码
// u 只是一个变量名,你可以叫它 self, me 或者 u
func (u User) Say() {
    fmt.Println(u.Name) // u 的指向在定义时就写死了,永远不会丢
}

🪝 思维钩子:Go 的方法绑定极像 User.prototype.say = ...。这种设计让逻辑复用变得极其简单,且没有运行时的上下文陷阱。


3. 权限的大小写命令:最简单的隐藏规则

在 TS 中,我们写 private。在 Go 中,你只需按下 Shift 键。

TypeScript(关键字控制)

typescript 复制代码
class User {
    public name: string;
    private age: number; // 靠关键字限制访问
}

Go(首字母定生死)

go 复制代码
type User struct {
    Name string // 首字母大写:外部包可见 (Public)
    age  int    // 首字母小写:仅限本包可见 (Private)
}

🪝 思维钩子:这是 Go 的"行政命令"。如果你在 A 包定义了 age,在 B 包里你连提示都敲不出来。调用处必须严格遵守定义处的大小写,没有模糊地带。


4. 指针、原件与复印机:a := b 的终极实验

这是 TS 程序员转 Go 时最容易产生 Bug 的地方。在 TS 里,对象赋值是引用;在 Go 里,一切赋值皆拷贝。

TypeScript(自动引用)

ini 复制代码
const u1 = { name: "Alice" };
const u2 = u1; 
u2.name = "Bob";
console.log(u1.name); // "Bob" (两人共用一个地址)

Go(默认复印机模式)

go 复制代码
u1 := User{Name: "Alice"}
u2 := u1      // 发生物理拷贝!u2 是 u1 的一个完整副本
u2.Name = "Bob"
fmt.Println(u1.Name) // "Alice" (u1 根本没动)

u3 := &u1     // 这才是拿到了 u1 的钥匙(指针)
u3.Name = "Bob"
fmt.Println(u1.Name) // "Bob" (原件被修改了)

🪝 思维钩子:a := b 是盖了一座一模一样的房子;a := &b 是把房子的钥匙交出去。


5. 契约与传参:强指针约束

💡 注意:为了从 TS 视角更好理解 Go 的严谨性,请看下表。在 Go 中,类型契约是不可妥协的。

场景 Go 表现 思维入口
函数要求 *User(指针) 你传 User(值) ❌ 编译报错:类型不匹配
函数要求 User(值) 你传 *User(指针) ❌ 编译报错:原件不能直接塞进复印机

🪝 思维钩子:Go 不支持隐式地址转换。当你写下 & 的那一刻,你在提醒自己:"我要交出修改原件的权限了"。


6. 工程组织:go.mod 对标 package.json

Go 的依赖管理不再有臃肿的 node_modules,它更清爽,但也更严格。

  • 导入逻辑:Go 导入的是文件夹(Package),而不是单个文件。

  • 版本管理:

    • go.modpackage.json(记录主依赖版本)
    • go.sumpackage-lock.json(记录哈希,防止内容篡改)

🪝 思维钩子:运行 go mod tidy 就像 npm install。它会自动扫描代码中的 import 路径,下载缺失包并剔除冗余包。


下篇预告:

我们将进入 Go 语言最迷人的部分:并发(Goroutine) 与 通道(Channel)。为什么 Go 处理万级并发轻而易举?为什么接口里不能定义变量?我们下篇见。

相关推荐
铁皮饭盒13 分钟前
bun直接tsx,优雅!
javascript·后端
_柳青杨2 小时前
一文吃透 Node.js 事件循环:从原理到 Node 20+ 重大变更
javascript·后端
唐青枫2 小时前
别再把 interface 当万能盒子:Go 接口从隐式实现到项目解耦
go
JieE21213 小时前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
冬奇Lab15 小时前
AI Workflow 定义的四次演进:从 Markdown 到 JS 脚本,再到分布式多 Agent
javascript·人工智能·agent
一颗烂土豆21 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
kyriewen1 天前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly1 天前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
假如让我当三天老蒯1 天前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒1 天前
Bun 哪比 Node.js 快?
javascript·后端