分类 技术志 下的文章

AI 编码工具“真香”还是“智商税”?一位资深码农的“挑衅”与Go开发者的反思

本文永久链接 – https://tonybai.com/2025/06/03/provocation-about-ai-assisted-programming

大家好,我是Tony Bai。

最近,fly.io 博客上该公司开发者 Thomas Ptacek 的一篇题为《My AI Skeptic Friends Are All Nuts》的文章,在开发者社区掀起了不小的波澜,一度登顶HN。Ptacek 以一位自称“严肃开发者”(从C语言到Go、Rust均有涉猎)的口吻,向那些对 AI 辅助编程持怀疑态度的“聪明朋友们”发出了略带“挑衅”的宣言:“即使 LLM 今天停止所有进展,它仍然是我职业生涯中发生的第二重要的事情”

这篇文章的观点之鲜明、论证之犀利,让我印象深刻。恰逢 前期Google I/O 2025 大会再次展示了 Gemini 等 AI 模型在编码领域的惊人进展,我们不禁要问:AI 编码工具,究竟是能极大提升生产力的“真香”利器,还是又一轮被过度炒作的“智商税”?作为开发者,特别是 Gopher,我们又该如何看待和应对这场正在发生的变革?

在这篇文章中,我就和大家一起来看看 Thomas Ptacek 对AI辅助编程演进的犀利观点以及他的反思。看看你是否认同他的想法。

误区澄清:现代 AI 辅助编程早已不是“复制粘贴”

Ptacek 在文章开篇就点出了一个关键问题:很多人对 AI 辅助编程的印象,还停留在半年前甚至两年前的水平。他写道:“如果你在6个月前(或者,天哪,两年前用Copilot的时候)尝试使用LLM编码并失败了,那么你并没有在做大多数严肃的LLM辅助编码者正在做的事情”。

那么,现在“严肃的LLM辅助编码者”在做什么呢?Ptacek 强调,他们使用的是 Agent (智能体)。这些 AI Agent 不再仅仅是根据提示生成代码片段让你复制粘贴,它们能够:

  • 自主地在你的代码库中进行探索。
  • 直接创建和修改文件。
  • 运行各种工具, 如编译器、测试框架、linter、formatter 等。
  • 与 Git 等版本控制系统交互。
  • 根据编译和测试结果进行迭代和修正。
  • 通过 MCP 或类似机制调用你设置的任意工具。

Ptacek强调:如果你对 AI 编码的印象还停留在 ChatGPT 网页上简单问答然后手动复制代码,那么你可能真的低估了当前 AI Agent 所能达到的自动化和智能化水平。

AI Agent 如何提升编码效率?Ptacek 的“积极案例”

Ptacek 认为,LLM(通过 Agent)能够极大地提升编码效率,主要体现在以下几个方面:

  1. 处理“乏味代码”: LLM 可以编写你需要编写的大部分乏味代码。而大多数项目中的大多数代码都是乏味的。这能让开发者从重复性的工作中解放出来,更快地进入“调整代码并立即看到效果更好”的“黄金时刻 (golden moment)”,获得即时反馈的“多巴胺冲击”。

  2. 克服项目启动的“惯性”: 面对一个新项目,繁琐的初始设置、依赖管理、基础架构搭建等往往令人望而却步。LLM Agent 可以被指示去“搞定这些破事,直接将你带到“事情几乎可以工作”的阶段。

  3. 自动化“苦差事”: 那些你不想做但又必须做的“脏活累活”,比如大规模的单元测试重构,完全可以交给 AI Agent 在虚拟机里折腾几个小时,然后带着一个 PR 回来。这反而会“逼迫”你去做“真正的工作 (real work)”。

回应常见的质疑:Ptacek 的“辩护”

Ptacek 在文章中也针对开发者对 AI 编码的常见质疑进行了犀利的回击,这些回应也为我们思考 Go 语言在 AI 时代的定位提供了新的视角。

  • 关于代码质量与审查责任——“你根本不知道它写的是什么!”

Ptacek强调,开发者始终对合并到 main 分支的代码负责,无论是否使用 LLM。 LLM 生成的代码是“可知的”,你需要阅读它,甚至花时间将其调整为你自己的风格。如果连 LLM 生成的“乏味、重复”的代码都难以理解和消化,那可能是开发人员的“技能问题”。

  • 关于“幻觉 (hallucination)”问题——“它会编造不存在的API!”

Ptacek 认为,对于编程而言,Agent 通过工具链(linting、编译、运行测试)形成的闭环反馈,已经(或多或少地)解决了“幻觉”问题。“如果它们的LLM编造了一个新的函数签名,Agent会看到错误。它们将其反馈给LLM,LLM会说‘哦,是的,我完全是编造的’,然后重试”。这里不能不提到** Go 语言的快速编译特性,使得这种“试错-反馈-修正”的闭环能够非常高效地运转。同时,Go 强大的标准库和清晰的 API 设计,是否也能减少 LLM“编造”API 的概率,或者使其更容易被工具链检测出来。

  • 关于“代码像初级开发者写的”——“质量太差!”

Ptacek 回应:“一个实习生一个月要花20美元吗?因为 Cursor.ai 就是这个价钱”。他认为,高级开发者的职责之一就是让能力稍逊的编码者(无论是人类还是“智能体”)变得高效。使用好 Agent 本身就是一项技能和一项涉及提示、索引和(尤其是)工具链的工程项目。 LLM 只有在你允许的情况下才会产生劣质代码。

  • 关于“不擅长特定语言 (如 Rust)”——“它写不了我的 Rust!”

Ptacek 认为这更多是语言生态和工具链成熟度的问题,而非 LLM 能力的根本缺陷。他特别指出:“我主要用 Go 工作……Go 恰到好处的类型安全、广泛的标准库以及推崇(通常是重复性)惯用法的文化。LLM 在生成 Go 代码方面表现出色。” 想必很多Go开发者也有着与Ptacek相同的感受,这是 Go 语言在 AI 辅助编程时代的一个显著优势! Go 的简洁性、明确性、强大的标准库覆盖、以及社区对代码规范和惯用法的重视(例如 Effective Go),使得 Go 代码的模式相对统一和可预测,这为 LLM 的学习和生成提供了极大的便利。

对“手工艺精神”与“平庸代码”的再思考

Ptacek 对软件开发中的“手工艺精神”和对“平庸代码”的过度排斥也提出了批判。

  • 他认为:专业软件开发者的工作是用代码为人们解决实际问题。在日常工作中,我们不是工匠。过度追求代码的“优雅”而忽视实际产出,可能是“自我安慰的yak-shaving(指做无关紧要的琐事)”。

  • 对于“平庸代码”,他认为:开发者都喜欢对代码自吹自擂。他们担心LLM降低了质量的“天花板”。也许吧。但它们也提高了“地板”。LLM 生成的“平庸但彻底”的代码,可能比人类开发者“抖机灵”但引入缺陷的代码更有价值。

这也引发我们思考:在追求卓越工程的同时,我们是否也应该更务实地看待不同场景下对代码质量的不同要求?LLM 是否能帮助我们更高效地处理那些“允许平庸”但又耗时耗力的部分,从而让我们能将精力投入到真正需要人类智慧和创造力的核心工作中?

Go 开发者如何拥抱 AI Agent 的时代?

Ptacek 的文章,无论你是否完全认同其所有观点,都为我们描绘了一个 AI Agent 深度参与软件开发的未来图景。作为 Gopher,我们应该如何应对?

  1. 更新认知,拥抱变化: 首先要认识到,现代 AI 辅助编程已经远超简单的代码补全。应该主动去了解和体验基于 Agent 的编码工具。
  2. 学习与 AI Agent 高效协作: 掌握提示工程技巧,学会如何清晰地向 Agent表达需求、提供上下文、引导其生成和修改代码。
  3. 发挥 Go 语言的优势: 利用 Go 的简洁性、强大的标准库、快速的编译和测试工具链,为 AI Agent 构建高效的开发和反馈环境。思考如何让 Go 代码对 AI 更“友好”。
  4. 提升自身的核心价值: 将精力更多地投入到 AI 难以替代的领域:复杂系统设计、架构决策、需求理解与抽象、创新思维、以及对 Go 底层原理和并发模型的深刻理解。
  5. 参与构建 Go 的 AI Agent 生态: Go 语言本身非常适合构建 CLI 工具和后端服务。我们是否可以利用 Go 来创建更强大的、针对 Go 开发的 Agent 辅助工具或平台?

小结:保持开放,主动实践,与 AI 共舞

AI 编码工具究竟是“真香”还是“智商税”?或许答案因人而异,也因我们如何使用它而异。但 Thomas Ptacek 的“挑衅”至少提醒我们,不能用静止的眼光看待飞速发展的技术。

AI 辅助编程的浪潮已然到来。对于我们 Gopher 而言,Go 语言的特性使其在这波浪潮中具有独特的优势。与其固守过去的经验和偏见,不如保持开放的心态,主动去实践和探索,让 AI Agent 成为我们提升自身能力、加速项目交付、并最终能专注于更有创造性工作的强大伙伴。

毕竟,正如 Ptacek 所说,当他那些“聪明的怀疑论朋友们”最终接受并开始使用这些工具时,他们将会让编码 Agent 比今天强大得多。

而我们,又怎能置身事外呢?


聊一聊,也帮个忙:

  • 你目前在工作中使用 AI 辅助编程工具(如 Copilot, Cursor.ai, Gemini Code Assist,Trae等)的体验如何?它在哪些方面帮助了你,又有哪些不足?
  • Ptacek 文章中对 AI 编码的哪个观点让你印象最深刻?你同意还是反对?为什么?
  • 你认为 Go 语言在 AI 辅助编程时代,还有哪些可以进一步优化的方向,以更好地与 LLM Agent 结合?

欢迎在评论区留下你的思考和经验。如果你觉得这篇文章提供了一个值得探讨的视角,也请转发给你身边的开发者朋友们,一起参与这场关于 AI 与编程未来的讨论!

想与我进行更深入的 Go 语言、AI 赋能开发与技术趋势交流吗? 欢迎加入我的“Go & AI 精进营”知识星球

img{512x368}

我们星球见!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

Go的简洁性之辩:轻量级匿名函数提案为何七年悬而未决?

本文永久链接 – https://tonybai.com/2025/06/03/lightweight-anonymous-func-syntax

大家好,我是Tony Bai。

自2017年提出以来,Go语言关于引入轻量级匿名函数语法的提案(Issue #21498)一直是社区讨论的焦点。该提案旨在提供一种更简洁的方式来定义匿名函数,尤其是当函数类型可以从上下文推断时,从而减少样板代码,提升代码的可读性和编写效率。然而,历经七年多的广泛讨论、多种语法方案的提出与激辩,以及来自核心团队成员的实验与分析,截至 2025年5 月底,官方对该提案的最新立场是“可能被拒绝 (likely declined)”,尽管问题仍保持开放以供未来考虑。近期该issue又冲上Go issue热度榜,让我有了对该提案做一个简单解读的冲动。在本文中,我将和大家一起探讨该提案的核心动机、社区的主要观点与分歧、面临的挑战,以及这一最新倾向对 Go 语言和开发者的潜在影响。

冗余之痛:当前匿名函数的困境

在Go中,匿名函数的标准写法是

func(参数列表) (返回类型列表) {
    函数体
}

虽然这种语法明确且一致,但在许多场景下,尤其是作为回调函数或在函数式编程风格(如配合泛型和迭代器使用)中,参数和返回类型往往可以从上下文清晰推断,此时显式声明则显得冗余。

提案发起者 Neil (neild) 给出了一个经典的例子:

func compute(fn func(float64, float64) float64) float64 {
    return fn(3, 4)
}

// 当前写法,类型声明重复
var _ = compute(func(a, b float64) float64 { return a + b })

许多现代语言,如 Scala ((x, y) => x + y 或 _ + _) 和 Rust (|x, y| { x + y }),都提供了更简洁的 lambda 表达式语法,允许在类型可推断时省略它们。这种简洁性被认为可以提高代码的信噪比,让开发者更专注于业务逻辑。

Go匿名函数常见的痛点场景包括:

  • 回调函数:如 http.HandlerFunc、errgroup.Group.Go、strings.TrimFunc。
  • 泛型辅助函数:随着 Go 1.18 泛型的引入,如 slices.SortFunc、maps.DeleteFunc 以及设想中的 Map/Filter/Reduce 等操作,匿名函数的应用更加广泛,其冗余性也更为凸显。
  • 迭代器:Go 1.23 引入的 range over func 迭代器特性,也使得将函数作为序列或转换器传递成为常态,轻量级匿名函数能显著改善其体验(如 #61898 x/exp/xiter 提案的讨论中多次提及)。正如一些开发者指出的,结合迭代器使用时,现有匿名函数语法会使代码显得冗长。

提案核心:轻量级语法的设想

该提案的核心思想是引入一种“非类型化函数字面量 (untyped function literal)”,其类型可以从赋值上下文(如变量赋值、函数参数传递)中推断得出。提案初期并未限定具体语法,而是鼓励社区探讨各种可能性。

Go team的AI 生成的总结指出,讨论中浮现的语法思路主要可以归为以下几种:

  1. 箭头函数风格 (Arrow Function Style): 借鉴 JavaScript, Scala, C#, Java 等。

    • 例如:(x, y) => { x + y } 或 (x,y) => x+y
  2. 保留 func 关键字并进行变体:

    • 例如:func a, b { a+b } (省略参数括号)
    • func(a,b): a+b (使用冒号分隔)
    • func { x, y | return x < y } (参数列表移入花括号,使用 | 或 -> 分隔)
  3. 基于现有语法的类型推断改进:

    • 例如:允许在 func(a _, b _) _ { return a + b } 中使用 _ 作为类型占位符。

其核心优势在于:

  • 减少样板代码: 省略冗余的类型声明。
  • 提升可读性(对部分人而言): 使代码更紧凑,逻辑更突出。
  • 促进函数式编程风格: 降低使用高阶函数和回调的心理门槛。

社区的激辩:争议焦点与权衡

该提案引发了 Go 社区长达数年的激烈讨论,根据 Robert Griesemer 提供的 AI上述总结 和整个讨论链,主要争议点包括:

1. 可读性 vs. 简洁性

  • 支持简洁方: 认为在类型明确的上下文中,重复声明类型是视觉噪音。简洁的语法能让代码更易于速读和理解,尤其是在函数式链式调用中。他们认为 Go 已经通过 := 接受了类型推断带来的简洁性。
  • 强调显式方: 以 Dave Cheney 的名言“Clear is better than clever” 为代表,一些开发者认为显式类型声明增强了代码的自文档性和可维护性。他们担心过度省略类型信息会增加认知负担,尤其对于初学者或在没有强大 IDE 支持的情况下阅读代码。Go密码学前负责人FiloSottile 指出,在阅读不熟悉的代码时,缺少类型信息会迫使其跳转到定义或依赖 IDE。Go元老Ian Lance Taylor也表达了对当前显式语法的肯定,认为其对读者而言清晰度很高。

2. 语法选择的困境

这是提案迟迟未能落地的最主要原因之一。社区提出了数十种不同的语法变体,但均未能形成压倒性的共识。

箭头语法 (=> 或 ->):

  • 优点: 许多开发者因在其他语言中的使用经验而感到熟悉,被认为非常简洁。Jimmy Frasche 的语言调查显示这是许多现代语言的选择。
  • 缺点: 一些人认为它“不像 Go”,=> 可能与 >= 或 <= 在视觉上产生混淆,-> 可能与通道操作 <- 混淆 。Robert Griesemer指出,虽然 (x, y) => x + y 感觉自然,但 (x, y) => { … } 对于 Go 而言感觉奇怪。Ian Lance Taylor也表达了对箭头符号的不完全满意,认为在某些代码上下文中可读性欠佳。

保留 func 并简化:

  • func params {} (省略参数括号):Ian Lance Taylor 和 Robert Griesemer 曾探讨过此形式。主要问题在于 func a, b {} 在函数调用参数列表中可能与多个参数混淆。
  • func { params | body } 或 func { params -> body }:Griesemer 在后期倾向于这种将参数列表置于花括号内的形式,认为 func { 可以明确指示轻量级函数字面量。| 用于语句体,-> (可选地) 用于单表达式体。Jimmy Frasche 对此形式的“DSL感”提出异议,认为其借鉴的 Smalltalk/Ruby 风格在 Go 中缺乏相应的上下文。

其他符号:

如使用冒号 func(a,b): expr ,或 _ 作为类型占位符。Griesemer认为 _ 作为类型占位符会产生混淆。

Robert Griesemer 进行的实验表明,func 后不带括号的参数列表 (func x, y { … }) 在实际 Go 代码中看起来奇怪,而箭头符号 (=>) 则“出乎意料地可读”。他后期的实验进一步对比了 (args) => { … } 和 func { args | … }。

3. 隐式返回 (Implicit Return)

对于单表达式函数体是否应该省略 return 关键字,也存在分歧。

  • 支持方: 认为这能进一步提升简洁性,是许多 lambda 语法的常见特性。
  • 反对方: 担心这会使返回行为不够明确,尤其是在 Go 允许多值返回和 ExpressionStmt (如函数调用本身可作为语句) 的情况下,可能会导致混淆或意外行为。例如 func { s -> fmt.Println(s) },如果 fmt.Println 有返回值,这个函数是返回了那些值,还是一个 void 函数?这需要非常明确的规则,并且可能依赖上下文。

4. 类型推断的复杂性与边界

虽然核心思想是“从上下文复制类型”,但当涉及到泛型时,推断会变得复杂。

  • Map((x) => { … }, []int{1,2,3}) :如果 Map 是 func Map[Tin, Tout any](in []Tin, f func(Tin) Tout) []Tout,那么 Tout 如何推断?是要求显式实例化 Map[int, ReturnType],还是尝试从 lambda 体内推断?后者将引入更复杂的双向类型推断,可能导致参数顺序影响推断结果,或在接口类型和具体类型之间产生微妙的 bug(如 typed nil 问题)。
  • neild 和 Merovius 指出,在很多情况下,可能需要显式提供泛型类型参数,或者接受推断的局限性。Griesemer提出的最新简化方案 (params) { statements } 明确指出其类型是从目标函数类型“复制”而来,且目标类型不能有未解析的类型参数。

5. 对 Go 语言哲学的影响

一些开发者担忧,引入过于灵活或“魔法”的语法会偏离 Go 语言简单、直接、显式优于隐式的核心哲学。他们认为现有语法虽冗长,但足够清晰,且 IDE 工具(如 gopls 的自动补全)已在一定程度上缓解了编写时的痛点。

开发者tmaxmax在其详尽的实验分析中指出,尽管标准库中单表达式函数字面量比例不高,但在其工作代码库中,这类情况更为常见,尤其是在使用泛型辅助函数如 Map、Filter 时。这表明不同代码库和使用场景下,对简洁语法的需求度可能存在差异。

最新动向:为何“可能被拒绝”?

在提案的最新comment说明中 (May 2025),明确指出:

The Go team has decided to not proceed with adding a lightweight anonymous function syntax at this time. The complexity cost associated with the new syntax, combined with the lack of clear consensus on the syntax, makes it difficult to justify moving forward. Therefore, this proposal is likely declined for now. The issue will remain open for future consideration, but the Go team does not intend to pursue this proposal for now.

这一立场由 Robert Griesemer 在上述AI 总结中进一步确认。核心原因可以归纳为:

  1. 缺乏明确共识: 尽管讨论热烈,但社区和核心团队均未就一个理想的、被广泛接受的语法方案达成一致。各种方案都有其支持者和反对者,以及各自的优缺点和潜在问题。
  2. 复杂性成本: 任何新语法都会增加语言的复杂性(学习、实现、工具链维护、文档等)。在收益不明确或争议较大的情况下,Go 团队倾向于保守。
  3. 潜在的微妙问题与可读性担忧: 正如讨论中浮现的各种边界情况(如类型推断与泛型的交互、隐式返回的歧义、私有类型访问限制等),引入新语法需要非常谨慎。Ian Lance Taylor 明确表达了对当前显式语法在可读性方面的肯定,并对省略类型信息可能带来的阅读障碍表示担忧。
  4. 已有工具的缓解作用: 正如一些评论者指出,IDE 的自动补全功能在一定程度上减轻了编写冗长函数字面量的痛苦。

Robert Griesemer进一步总结,将备选方案缩小到 (params) { statements }, (params) { statements }, 和 (params) -> { statements } (或 =>),并指出即使是这些方案,也各有其不完美之处。他强调了在没有明确压倒性优势方案和社区强烈共识的情况下,贸然推进的风险。

影响与未来展望

尽管 #21498 提案目前大概率会被搁置,但它所反映的开发者对于减少样板代码、提升特定场景下编码效率的诉求是真实存在的。

  • 对迭代器和泛型库的影响: 如果提案最终未被采纳,那么严重依赖回调函数的泛型库(如设想中的 xiter 或其他函数式集合库)在使用上将保持当前的冗余度。这可能会在一定程度上抑制纯函数式风格在 Go 中的发展,或者促使开发者寻求其他模式(例如,手写循环或构建更专门的辅助函数)。有开发者认为缺乏简洁的 lambda 语法是阻碍 Go 社区充分实验函数式特性(尤其是迭代器组合)的先决条件之一。

  • 社区的持续探索: 提案的开放状态意味着未来仍有讨论空间。如果 Go 语言在其他方面(如类型系统、元编程能力)发生演进,或者社区就某一特定语法方向形成更强共识,提案可能会被重新激活。tmaxmax 建议将讨论重心从无休止的语法细节转向更根本的动机和语义问题。

  • 工具的进步: IDE 和代码生成工具可能会继续发展,以进一步缓解手动编写完整函数字面量的繁琐。

  • 开发者习惯: Go 开发者将继续在现有语法框架内寻求平衡。对于高度重复的匿名函数模式,可能会更多地采用具名辅助函数或方法来封装。正如 adonovan 的实验所示,某些特定场景(如单 return 语句)可能更容易找到局部优化方案。

小结

Go 语言轻量级匿名函数语法的提案 #21498,是一场关于语言简洁性、可读性、一致性与演进方向的深刻大讨论。它暴露出在追求更现代编程范式便利性的同时,维护 Go 语言核心设计哲学的内在张力。虽然目前看来,由于缺乏明确共识和对复杂性的审慎态度,引入一种全新的、被广泛接受的简洁匿名函数语法道阻且长,但这场长达七年的讨论本身,已经为 Go 社区积累了宝贵的思考、实验数据和经验。未来,无论此提案走向何方,对代码清晰度和开发者体验的追求都将持续驱动 Go 语言的演进。Go 团队将持续观察语言的使用和社区的需求,在合适的时机可能会重新审视此类提案。


在 Go 语言的演进过程中,每一个提案的讨论都凝聚了社区的智慧和对这门语言深沉的热爱。轻量级匿名函数语法的提案,历经七年风雨,虽然目前官方倾向于搁置,但这扇门并未完全关闭。

对于 Go 开发者来说,这场旷日持久的讨论留下了哪些值得我们深思的问题?

  • 你认为在当前 Go 的语法体系下,匿名函数的冗余是亟待解决的痛点吗?或者你认为现有的显式声明更符合 Go 的哲学?
  • 在可读性、简洁性和语言复杂性之间,你认为 Go 应该如何权衡?
  • 如果未来 Go 语言采纳某种形式的轻量级匿名函数,你最期待哪种语法特性(例如,类型推断、隐式返回、特定符号)?
  • 你是否在自己的项目中因为匿名函数的冗余而选择过其他编码模式?欢迎分享你的经验和看法。

我期待在评论区看到你的真知灼见,共同探讨 Go 语言的现在与未来!

img{512x368}


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats