MoreRSS

site iconEin Verne修改

软件工程师,开源爱好者,Linux用户和vimer开发者。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Ein Verne的 RSS 预览

Claw Cloud Run 提供永久免费的服务器

2025-04-17 13:00:00

Claw Cloud Run 是 Claw Cloud 旗下的,类似 Vercel,Netlify 的在线开发和部署平台,可以部署非常多 SaaS 程序,包括 [[AList]],[[Appsmith]],[[Bytebase]],[[ChatGPT-Next-Web]], frp,[[Dify]] 等等非常多的服务。

e27XbsHxsG

目前 Claw Cloud Run 只需要注册,并且绑定一个超过 180 的 GitHub 账户,就可以永久免费获得 5 美元的月额度。

V8zCQ1Jve3

在每个可用的区域可以最多使用 4vCPU,8GB 内存,10GB 硬盘,并提供 10GB 的流量。

需要注意,5 美元的额度不能用来兑换 Hobby 套餐,只能在使用 Free 套餐的时候用来抵扣费用。

Lenny’s Newsletter 重磅福利:200 美元订阅换取 15000 美元 AI 工具包

2025-04-16 13:00:00

昨天,科技圈被一则消息刷屏:Lenny’s Newsletter 推出了一项令人难以置信的优惠 - 只需支付 200 美元的年度订阅费,用户就能获得包括 Cursor Pro、V0、Bolt、Lovable、Notion Pro、Superhuman 和 Perplexity Pro 在内的多款顶级 AI 工具,总价值接近 15000 美元。这一举措迅速在互联网圈引发热议,许多人惊叹于这个”不可思议的交易”。

Lenny Rachitsky:从 Airbnb 产品负责人到顶级 Newsletter 作者

Lenny Rachitsky 是谁?在成为知名 Newsletter 作者之前,他曾在 Airbnb 担任产品负责人长达 7 年。2012 年,他的创业公司”Localmind”(一个帮助旅行者获取当地居民推荐的平台)被 Airbnb 收购,随后他从工程领域转向产品团队。

2019 年,Lenny 离开 Airbnb 后,本打算继续创业,但他给自己设定了半年的探索期,想看看自己真正热爱做什么。他遵循一个简单的原则:做更多给自己带来能量的事,减少消耗能量的事。在这段探索期间,他在 Medium 上分享了一篇总结 Airbnb 工作经验的文章,意外获得了 3 万点赞,甚至被 Airbnb 的 CEO 转发给全公司。

受到 Andreessen Horowitz 合伙人 Andrew Chen 的启发,Lenny 意识到当你找到既热爱又被市场认可的事情时,应该加倍投入。于是,他创建了自己的周刊”Lenny’s Newsletter”。

Lenny’s Newsletter 的惊人增长

Lenny 的 Newsletter 专注于产品管理、增长策略和职业发展等主题,以实用性和高质量内容著称。从 2019 年开始,他的订阅者数量呈爆炸式增长:

  • 2020 年 4 月,他推出付费版本时,拥有 13,000 名免费订阅者和 486 名付费订阅者,年收入约 56,000 美元
  • 到 2020 年底,增长至 45,000 名免费订阅者和 3,300 名付费订阅者,年收入约 360,000 美元
  • 目前,他的 Newsletter 已拥有超过 270,000 名订阅者,成为 Substack 平台上排名第一的商业类周刊

除了 Newsletter,Lenny 还主持全球排名前十的科技播客,运营一个拥有 10,000 多名创始人和产品领导者的社区,管理产品职位招聘板,并活跃于天使投资领域。

Lenny 成功的秘诀

持续输出高价值内容

Lenny 的成功不是偶然的。他每周二都会为付费订阅用户发布全新的深度文章,每周六还有”社区智慧”专栏,精选 Slack 社区的精彩讨论。他的内容选择策略很简单:

“我保留一个长长的想写的主题列表(目前有约 50 个),并大致了解接下来 2-3 篇文章的内容。每个周二临近时,我会选择本周最想写的主题。我优先考虑自己的好奇心而非人们想要的内容,因为这总能带来最好的结果。”

巧用社交媒体传播

Lenny 善于利用社交媒体扩大影响力。他会在 LinkedIn 和 Twitter 上分享短小精悍、引人入胜的片段,吸引用户点击查看完整内容。他的策略是”不要吝啬分享黄金内容,而是直接展示出来。一旦人们看到你拥有的价值,他们会主动寻找你。”

原创深度研究内容

Lenny 的 Newsletter 成功很大程度上归功于他的原创深度研究。他曾花数月深入采访 Uber、Zillow 等公司高管,研究他们的市场增长策略。这类文章迅速流传,大幅提升了他的订阅数量。

“如果看我的整个增长轨迹,50%的增长来自仅仅两篇文章,这很疯狂。一方面,大型史诗级文章非常强大;另一方面,另外 50%的增长来自日常的每周常规文章。”

200 美元换 15000 美元 AI 工具包:背后的逻辑

那么,Lenny 是如何做到用 200 美元的 Newsletter 年订阅费,换取价值近 15000 美元的 AI 工具包的呢?

2025 年 2 月 4 日,Lenny 首次宣布了一个”史上最伟大的产品捆绑包”,包括 Granola、Notion、Superhuman、Linear 和 Perplexity 的一年免费使用权。到了 2025 年 4 月 15 日,这个优惠变得更加惊人,增加了 Cursor、v0、Replit、Lovable 和 Bolt 等热门 AI 工具。

这一切的核心在于:他创造的价值已经获得整个科技圈的认可,资源主动找上门。Lenny 的播客曾采访过 V0 的创始人、OpenAI 的 CPO、Superhuman 的创始人等科技界重量级人物。拥有这种级别的人脉和影响力,推出看似夸张的福利套餐就变得合情合理了。

给创作者的启示

Lenny 的成功故事给所有内容创作者提供了宝贵的启示:

  1. 找到自己真正热爱的领域:Lenny 在离开 Airbnb 后,通过半年的探索发现了自己对写作的热爱。
  2. 持续创造高价值内容:正如 Lenny 所说,”如果你为人们创造价值,他们自然会想要关注你、订阅你并与朋友分享。这是我成功的秘诀:为受众持续提供价值。”
  3. 不要害怕分享:找出你的受众在哪里,尝试在他们面前展示自己。在社交媒体上分享你的内容,写客座文章,参加播客,联系有影响力的人。
  4. 长期坚持:你的受众不会在一夜之间增长,所以不要因为数字没有达到初始预期而感到失望。这只是一段更长旅程的开始。

正如 Dharmesh Shah(HubSpot 联合创始人)所说:”获得你想要的最好方法是配得上你想要的东西。”对于 Newsletter 来说,最好的增长方式就是值得获得订阅者的注意力。创造令人惊叹的内容,尽可能打动他们的心。

高价值的人脉,源于高价值的内容。看清楚自己手中已有的资源,找到真正热爱的事情,最重要的是,立即开始创造,并分享给全世界,你永远也不知道哪个小小的创作,会意外改变你的命运。

related

  • [[Lenny Newsletter]]

Google Agent2Agent 协议

2025-04-10 13:00:00

现如今,AI Agent 已经能够自主处理非常多重复和复杂的任务,并且越来越多的企业也正在构建和部署 AI Agent。就在刚刚过去的 Google Cloud Next 2025 大会上 Google 宣布了全新的 Agent2Agent (A2A)协议。这是一个开放的 AI Agent 协议,目的是为了建立 AI Agent 框架之间的联系,实现安全高效的协作。

什么是 AI Agent

[[AI Agent]] 是一个能自主感知,并进行决策,执行任务的智能系统,核心是利用 AI,尤其是大语言模型 LLM,完成复杂任务,模仿人类的智能行为。

MCP 是什么

MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 于 2024 年推出的一种开放标准,通过统一的协议,将大型语言模型(LLM)与外部数据源、工具和功能连接起来,以实现更高效的交互和扩展能力。

举一个简单的例子来说,MCP 就像是给 LLM 配置了一个标准化的工具箱和资源包,让 LLM 知道如何正确地使用工具。比如说 LLM 想要查询天气时,MCP 就会告诉 LLM 去这个地方,使用什么样的格式,查询获取天气数据。

Agent2Agent 是什么?

Google 开源的 AI Agent 交互协议——Agent2Agent Protocol(简称 A2A)。

A2A 将打破系统之间的壁垒,对 Agent 的能力、跨平台协作、执行效率产生质的改变,支持 Atlassian、Box、Cohere、Intuit、Langchain、MongoDB、PayPal、Salesforce、SAP、ServiceNow、UKG 和 Workday 等主流企业应用平台。

谷歌还发布了 Agent 开发套件 ADK,内部测试工具 Agent Engine,新的 Agent 市场等。

A2A 设计原则

A2A 是一种开放协议,为 Agent 提供一种标准的交互形式,不受底层框架或供应商的限制。

举一个简单的例子,比如一家互联网公司内部使用多个企业协作服务,比如利用 Atlassian 作为项目管理,Slack 作为企业内部沟通工具,Dropbox 作为文件存储和共享,在此之前这些平台上的 AI Agent 是无法自由通信的,如果要实现沟通只能通过 API 调用或者花费额外的开发,但是通过 A2A 协议,这些平台可以自由地安全地交互数据。

如果上面这一些企业内的使用场景很难想象的话,那再举一个例子,比如说用户让 LLM 指定一个旅游计划(比如东京 7 日游),那么 A2A 就会通过内置的 Agent,向提供天气获取的 Agent 获取天气预告,向提供餐厅介绍和预订服务的 Agent 查询相关的美食并预订,向提供地图和导航能力的 Agent 查询并制定完整的路线。

MCP 虽然可以提供对应的能力,但是 A2A 更像是一个强大版本,并且可以扩展的服务,A2A 没有限制 Agent 的范围,可以是一个本地服务, 也可以是一个在线服务,可以是一个应用,甚至也可以是另外一个 LLM。

五个关键原则:

  • 多代理,A2A 专注于 Agent 在自然语言,非结构化的模式下协作,不共享内存,工具和上下文
    • AI Agent 无需暴露内部推理过程和状态
  • 基于现有,流行的标准构建,包括 HTTP,服务器端事件([[Server Sent Events]]),JSON-RPC 等
    • 不重复造轮子
  • A2A 支持企业级认证和授权,A2A 协议可以快速通过身份验证,安全地获取数据
    • 解决数据安全问题
  • 支持长时间任务,支持快速任务或者可能需要很长时间的深入研究,A2A 可以向用户提供实时反馈,通知,状态更新
    • 支持异步任务,长时间任务管理
  • Agent 不仅限于文本,支持各种模态,包括音频,图像,视频
    • 多模态能力

A2A 协议借鉴了分布式系统的思想,每一个 AI Agent 都可以作为独立服务提供商,通过标准的接口进行通信,任何的 LLM 开发框架,包括 [[CrewAI]], [[LangChain]],[[LangGraph]],[[GenKit]],Google 的 Agent Developer Kit(ADK)都可以实现与其他代理协作。

工作原理

客户端 Agent (Client Agent)和远程 Agent (Remote Agent )通信,客户端 Agent 负责制定和传达任务,远程 Agent 则根据这些任务采取行动,提供信息或执行操作。

4PH5PeUcAn

关键点

  • 能力发现,Agent 利用 JSON 形式来定义其能力,称为 Agent Card,让客户端 Agent 识别哪个远程 Agent 最适合执行特定任务,一旦确定了合适的远程 Agent,客户端 Agent 就会利用 A2A 协议进行通信,将任务分配给它。
  • 任务管理,对于一些简单的任务,可以立即完成,对于复杂,长期的任务,Agent 可以保持沟通,并更新状态,完成时,输出称为「Artifact」工件
  • 协作,A2A 支持 Agent 之间协作,Agent 之间可以相互发送信息,包含上下文信息,回复,工件或用户指令。
  • 用户协商,每一条消息包含 parts,即完成形成的内容片段,例如生成的图像,每个 part 都有指定的内容类型,允许客户端和远程 Agent 协商所需要的正确格式。

PCl3

Google 在官方博客中还给出了一个真实的 A2A 案例,比如要招聘软件工程师,那么在统一的界面中,比如 Agentspace,用户可以直接委托 Agent 寻找符合职位,工作地点,技能要求的候选人。然后 Agent 会自动和其他专业 Agent 互动,寻找潜在的候选人。用户收到建议之后,可以指示 Agent 经一步安排面试等。

关键概念

Agent Card

Agent Card(代理卡),这是一个描述 Agent 名字,能力,版本的 JSON 定义,可以托管在域名的固定路径下,通过网络请求可以发现和使用。

Agent Card 中可以定义 Agent 的名字,描述,版本,技能(描述 Agent 的能力)

Agent Card 位置可以存放在 /.well-known/agent.json 文件中。

区别

A2A vs MCP

MCP 的核心原则是描述 LLM 和工具资源之间的交互,A2A 则更关注 Agent 之间的交互,Agent 之间如何相互发现,理解彼此的能力,并自主协商如何协作。A2A 是对 Anthropic MCP 协议的补充,MCP 为 Agent 提供了使用的工具和上下文,A2A 协议则是在 Agent 之间构建了一个开放的协议。

Agent Development Kit

Google 在发布 A2A 协议草案的同时也公开了 Agent Development Kit (ADK) 这样的 Agent 开发套件。1

reference

HostHatch 私有网络配置记录

2025-04-09 13:00:00

我一直有使用 HostHatch 的 VPS,这也是我人生中购买的第一台新加坡的服务器,HostHatch 的服务一直比较稳定,可惜的是到国内的网络不太行,延迟比较高。但好在 2 核 8G 内存,40 G 存储,两年只要 68 美元,所以也就又续费了。

但是在续费的过程中点开后台发现 HostHatch 更新了一个私有网络(Private Networking)的功能,根据官方的说法,需要在 VM 上开启私有网络,那么就可以获得一个额外的网络接口,可以通过该网络接口和同一个区域中的其他 VM 之间通信。但是无法通过此接口访问任何外部网络。

Private Networking

如果 VPS(VM)开启私有网络之后,会与自己唯一的 VLAN/VXLAN 隔离,可以为其分配任何的 IPv4 或 IPv6 地址,HostHatch 不会在这些网络上提供任何自动地址分配或者 DHCP,如果将所有的主机配置到同一个子网中,就无需设置任何手动路由或者网关,比如 192.168.10.1/24 和 192.168.10.2/24。

如果在 VM 创建时添加,或者在启用 VM 之后重新安装,此接口将自动重命名为 eth1,可以通过其 MAC 地址来识别,以 00:22 开头,可以在这些接口上使用 MTU 9000 以实现最大吞吐量。

此接口的带宽是无限的,不计入服务器每个月的带宽使用。

配置

这里我自己只使用 Ubuntu/Debian 系统,所以只以此为例,如果您使用 CentOS 或者 AlmaLinux 可以自行参考官方文档设置。

首先识别接口名字

ip -o link | grep 00:22

创建新的 interfaces.d 文件,如果不相同,将 eth1 更改为接口名。创建 /etc/network/interfaces.d/90-private

auto eth1
iface eth1 inet static
    address 192.168.10.1/24

然后重启网络服务

sudo systemctl restart networking

Cursor Rules 为 AI 设限

2025-04-02 13:00:00

我自己使用 Cursor 已经有一段时间了,Cursor 提供了非常好用的代码补全,以及代码生成功能,但是在使用的过程中难免也发现了一些问题,最近看到 Cursor 推出了这个 Cursor Rules,看到了官方尝试来解决一些问题,也正好以此契机来完整地介绍一下 Cursor Rule,给 AI 设定一些界限,规则,不让其过分地自由发挥以至于发生意想之外的错误。

什么是 Cursor Rules

Cursor Rules 本质上是一个控制 AI 模型行为的指令,可以将其理解成 Cursor「系统级别的 Prompt」。通过这些前置的规则,可以更好地约束 AI 生成代码的方向,按照我们自己特定的需求和标准来更好的辅助我们编码。

Cursor Rules 可以涵盖非常多的方面,包括编码规范,框架和库的使用,架构,目录,文件结构,文件质量和安全,测试,文档等等。

Cursor Rules 提供两种设置规则的方式

  • Project Rules,项目级别的规则,独属于项目配置,存储在 .cursor/rules 目录下,当匹配的文件被引用时,自动包含规则。
    • 在 Cursor 0.47.5 中,Project Rules 新增了 Rule Type 功能,可以更细致地定义规则类型
  • Global Rules,全局规则,适用于所有的项目,在 Cursor 设置中进行配置(Settings > General > Rules for AI)

Pxfh

如何编写 Cursor Rules

指定项目的技术栈

在 Cursor Rules 中指定当前项目使用的技术栈,可以让 Cursor 更好地根据这个技术栈来生成响应的代码。

命名规则

可以指定 AI 让其生成的变量名,方法名,类名等符合一定的命名风格,比如

  • 变量名使用 camelCase 驼峰
  • 常量使用全大小加下划线分割 MAX_VALUE
  • 类名使用大驼峰命名法 PascalCase

这样设置之后,AI 生成的代码更加可控,也不需要自己手动去重命名。

注释代码

可以让 AI 生成的代码增加一些可读的注释,默认情况下 AI 生成的代码会缺少文档和相关的注释,特别是在复杂逻辑,函数时,可以预定义一些内容,让 AI 在生成时对应的生成注释和文档,比如

  • 所有的公开函数需要有功能注释,解释其输入和输出,以及方法作用
  • 复杂的函数或逻辑需要在行内注释

代码风格

每个开发团队都会有自己的代码风格和实践,比如代码缩进,函数长度,空行的使用,AI 生成的代码风格如果和团队的标准差异比较大的情况,可以自行设定代码风格规则,确保 AI 生成的代码风格一致。

其他的实践经验

  1. 具体代码优先:“DO NOT GIVE ME HIGH LEVEL SHIT, IF I ASK FOR FIX OR EXPLANATION, I WANT ACTUAL CODE OR EXPLANATION!!!” 这条规则直接要求 AI 提供具体的代码或解释,而不是抽象的高层次描述。
  2. 保持简洁:“Be terse”(简洁),这条规则要求 AI 省去无用的修饰词,直接提供有价值的信息。
  3. 预测需求:“Suggest solutions that I didn’t think about—anticipate my needs”,这条规则鼓励 AI 不仅解决当前问题,还要预测用户可能需要的解决方案。

个人使用经验

充分利用 Git 去保存阶段性生成的可用代码,Cursor 生成代码的以及批量修改文件的能力非常强大,但是同时也可能将已有的功能破坏,所以我个人的经验就是每次会新建分支,让 Cursor 就某一个功能提供修改,直到改到成功为止,并提交 Git。一旦发生问题可以追溯或者进行 revert。

其他参考

related

Flutter 教程系列一: freezed 使用

2025-03-23 13:00:00

不管在什么样的应用中,如果要处理大量的数据,不可避免的就是要定义大量的数据类用来装载和解析数据,在 Flutter 中也不例外,今天要介绍的这个 Freezed 库就是 Flutter 中用来作为数据类(data classes)代码生成的这样一款工具。

freezed 是什么

freezed 是一个 Flutter/Dart 生态系统中一个非常强大的代码生成工具,用于创建数据类,基于 Dart 的代码生成功能,通过自动生成 data classes, tagged unions, nested classes 和 clone 代码模板,大大减少了手动编写重复性代码的工作量。freezed 的设计非常类似 Java 生态中的 [[Lombok]],通过注解和代码生成来减少样板代码量。

尽管 Dart 很棒,但是在定义 Model 的时候还是非常乏味,编程者需要

  • 定义构造函数,属性
  • 重载 toString, == hashCode 等
  • 实现 copyWith 方法来 clone 对象
  • 处理序列化以及反序列化等

如果要实现这一些,一个 Model 可能就需要上百行代码,这不仅容易出错,而且还影响了代码易读性。freezed 就是设计用来来帮助开发者只需要关注定义 Model,而无需考虑其他。

比如一个简单的用户定义

class Person with _$Person {
  Person({
    required this.firstName;
    required this.lastName;
    required this.age;
  })
  final String firstName;
  final String lastName;
  final String age;
}

freezed 安装

为了使用 Freezed,需要依赖 build_runner 代码生成,首先安装 build_runner 和 Freezed,添加依赖到 pubspec.yaml 中。

通过命令行添加

flutter pub add freezed_annotation
flutter pub add dev:build_runner
flutter pub add dev:freezed
# if using freezed to generate fromJson/toJson, also add:
flutter pub add json_annotation
flutter pub add dev:json_serializable

直接修改 pubspec.yaml 文件

dependencies:
  flutter:
    sdk: flutter
  freezed_annotation: ^3.0.4
  json_annotation: ^4.0.6  # 如需JSON序列化支持

dev_dependencies:
  build_runner: ^2.3.2
  freezed: ^3.0.4
  json_serializable: ^6.5.4  # 如需JSON序列化支持

然后运行 flutter pub get

说明

  • build_runner 用来运行代码生成
  • freezed 是代码生成器
  • freezed_annotation,包含了 freezed 注解

运行代码生成

dart run build_runner watch -d
# or
flutter pub run build_runner build --delete-conflicting-outputs

和其他代码生成器需要的一样,freezed 需要导入 freezed 注解,并且需要使用 part 关键字

import 'package:freezed_annotation/freezed_annotation.dart';

part 'my_file.freezed.dart';

freezed 使用

为了避免与 JSON 序列化相关的警告,建议在项目根目录的analysis_options.yaml文件中添加以下配置

analyzer:
  errors:
    invalid_annotation_target: ignore

创建 Model

Freezed 提供两种方式来创建 data-classes

  • Primary constructors,定义构造函数,Freezed 生成关联字段
  • Classic classes,编写正常的 Dart 类,Freezed 只生成 toString/ == / copyWith

Primary constructors

Freezed 实现 Primary Constructors 通过 factory 关键字。

import 'package:freezed_annotation/freezed_annotation.dart';

// required: associates our `main.dart` with the code generated by Freezed
part 'main.freezed.dart';
// optional: Since our Person class is serializable, we must add this line.
// But if Person was not serializable, we could skip it.
part 'main.g.dart';

@freezed
abstract class Person with _$Person {
  const factory Person({
    required String firstName,
    required String lastName,
    required int age,
  }) = _Person;

  factory Person.fromJson(Map<String, Object?> json) => _$PersonFromJson(json);
}

定义了 Person

  • 属性
  • 使用了 @freezed 注解,类属性是不可变的
  • 定义了 fromJson,序列化和反序列化,Freezed 会添加 toJson 方法
  • Freezed 会自动生成 toString / == / hashCode / copyWith

执行命令

flutter pub run build_runner build --delete-conflicting-outputs

命令将生成 xxx.freezed.dart 文件,以及 xxx.g.dart 包含序列化相关的代码

如果有一些情况需要定义 getters 或者自定义方法,这个时候需要定义一个空的构造函数

@freezed
abstract class Person with _$Person {
  // Added constructor. Must not have any parameter
  const Person._();

  const factory Person(String name, {int? age}) = _Person;

  void method() {
    print('hello world');
  }
}

定义可变类

需要使用 @unfreezed

@unfreezed
abstract class Person with _$Person {
  factory Person({
    required String firstName,
    required String lastName,
    required final int age,
  }) = _Person;

  factory Person.fromJson(Map<String, Object?> json) => _$PersonFromJson(json);
}

姓名是可变的

void main() {
  var person = Person(firstName: 'John', lastName: 'Smith', age: 42);

  person.firstName = 'Mona';
  person.lastName = 'Lisa';
}

并且不会实现 == / hashCode 方法,所以下面的比较等于 false

void main() {
  var john = Person(firstName: 'John', lastName: 'Smith', age: 42);
  var john2 = Person(firstName: 'John', lastName: 'Smith', age: 42);

  print(john == john2); // false
}

让 Lists/Maps/Sets 可变

通常情况下,如果使用 @freezed ,那么内部属性如果使用 List/Map/Set 会自动变成不可变

@freezed
abstract class Example with _$Example {
  factory Example(List<int> list) = _Example;
}

void main() {
  var example = Example([]);
  example.list.add(42); // throws because we are mutating a collection
}

需要调整为

@Freezed(makeCollectionsUnmodifiable: false)
abstract class Example with _$Example {
  factory Example(List<int> list) = _Example;
}

void main() {
  var example = Example([]);
  example.list.add(42); // OK
}

Classic classes

和之前提到的 Primary constructors 相比,这个模式下,我们只需要定义普通的 Dart classes。

通常编写 constructor 和 fields 定义。

import 'package:freezed_annotation/freezed_annotation.dart';

// required: associates our `main.dart` with the code generated by Freezed
part 'main.freezed.dart';
// optional: Since our Person class is serializable, we must add this line.
// But if Person was not serializable, we could skip it.
part 'main.g.dart';

@freezed
@JsonSerializable()
class Person with _$Person {
  const Person({
    required this.firstName,
    required this.lastName,
    required this.age,
  });

  final String firstName;
  final String lastName;
  final int age;

  factory Person.fromJson(Map<String, Object?> json)
      => _$PersonFromJson(json);

  Map<String, Object?> toJson() => _$PersonToJson(this);
}

Freezed 会自动处理 copyWith / toString / == / hashCode 。

related

  • DartJ 是一个可以将 JSON 快速转变成 Dart 类定义的工具。