所属阶段:第二阶段「组件精讲」(第 4-15 课) 前置条件:第 4 课 本课收获:能对比通用与语言规则的差异,能为新语言草拟规则
一、本课概述
上节课我们学习了 10 个通用规则文件。这节课进入语言特定规则层:
- 继承机制 --- 语言规则如何"继承并覆盖"通用规则
- 覆盖案例 --- 真实的继承覆盖场景分析
- 14 种语言的规则结构 --- 每种语言通常有 5 个文件
- 添加新语言 --- 从零开始为一种新语言创建规则
这节课是 Rules 专题的收尾。学完后,你将完整掌握 ECC 的规则体系。
二、语言规则的继承机制
2.1 继承声明
每个语言规则文件的第一行(正文部分)必须以引用块声明继承关系:
markdown
> This file extends [common/coding-style.md](../common/coding-style.md) with Go specific content.
这行话的含义:
- 本文件继承 了
common/coding-style.md的所有规则 - 本文件只包含新增 或覆盖的部分
- 没有提及的通用规则仍然有效
2.2 paths 字段
语言规则通常有一个 paths frontmatter 字段,指定适用范围:
yaml
# rules/golang/coding-style.md
---
paths:
- "**/*.go"
- "**/go.mod"
- "**/go.sum"
---
yaml
# rules/typescript/coding-style.md
---
paths:
- "**/*.ts"
- "**/*.tsx"
- "**/*.js"
- "**/*.jsx"
---
这告诉 Claude:只在处理匹配这些 glob 模式的文件时应用语言特定规则。处理其他文件时,仅通用规则生效。
2.3 继承 vs 覆盖的判断
| 情况 | 行为 | 示例 |
|---|---|---|
| 语言规则新增了通用规则没有的内容 | 追加 | Go 新增 "Accept interfaces, return structs" |
| 语言规则重新定义了同一主题 | 覆盖 | Go 指针接收器覆盖通用不可变性 |
| 语言规则未提及某通用规则 | 继承 | 未提及 "函数 < 50 行" 则沿用 |
三、覆盖案例分析
3.1 Go 的指针接收器 --- 覆盖不可变性
通用规则 (common/coding-style.md):
Immutability --- CRITICAL: ALWAYS create new objects, NEVER mutate existing ones.
Go 规则 (rules/golang/coding-style.md):
go
// Go 惯用法:接受接口,返回结构体
// 使用指针接收器修改 struct 是 Go 的标准做法
func (u *User) UpdateEmail(email string) {
u.Email = email // 直接修改,这在 Go 中是惯用的
}
Go 的设计哲学中,指针接收器的可变性是语言核心特性。强制不可变会导致非惯用的代码。因此语言规则覆盖了通用规则。
通用规则中也标注了这种可能性:
Language note: This rule may be overridden by language-specific rules for languages where this pattern is not idiomatic.
3.2 Rust 的所有权系统 --- 增强不可变性
通用规则:不可变性是 CRITICAL。
Rust 规则 (rules/rust/coding-style.md):
rust
// Rust 变量默认不可变 --- 拥抱这一点
// 仅在需要修改时使用 let mut
let name = String::from("hello"); // 不可变
let mut counter = 0; // 显式声明可变
// 使用 Cow 实现按需分配
use std::borrow::Cow;
fn normalize(input: &str) -> Cow<'_, str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input)
}
}
Rust 不是覆盖不可变性,而是增强 它 --- Rust 的所有权系统在编译期强制执行不可变性,比通用规则的要求更严格。语言规则提供了 Rust 特有的实现方式(let vs let mut、Cow)。
3.3 Python 的 PEP 8 --- 覆盖格式规范
通用规则:通用的命名规范(camelCase/PascalCase/UPPER_SNAKE_CASE)。
Python 规则 (rules/python/coding-style.md):
python
# PEP 8 命名规范(覆盖通用规则)
# 函数和变量:snake_case(不是 camelCase)
def get_user_by_id(user_id: int) -> User:
pass
# 类:PascalCase(与通用规则一致)
class UserRepository:
pass
# 常量:UPPER_SNAKE_CASE(与通用规则一致)
MAX_RETRY_COUNT = 3
# 不可变数据结构
@dataclass(frozen=True)
class User:
name: str
email: str
Python 的 snake_case 函数命名覆盖了通用规则中的 camelCase 建议。但类命名和常量命名与通用规则保持一致。
3.4 TypeScript 的类型系统 --- 新增内容
TypeScript 规则 (rules/typescript/coding-style.md)新增了通用规则中没有的内容:
typescript
// 导出函数必须有显式类型
interface User {
firstName: string;
lastName: string;
}
export function formatUser(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
// 本地变量可以使用类型推断
const count = items.length; // TypeScript 自动推断为 number
这是新增(通用规则没有类型系统的要求),不是覆盖。
四、14 种语言的规则结构
4.1 支持的语言列表
ECC 当前支持 14 个语言/平台规则目录:
| 序号 | 目录 | 语言/平台 | 文件数 |
|---|---|---|---|
| 1 | golang/ |
Go | 5 |
| 2 | typescript/ |
TypeScript / JavaScript | 5 |
| 3 | python/ |
Python | 5 |
| 4 | rust/ |
Rust | 5 |
| 5 | swift/ |
Swift | 5 |
| 6 | java/ |
Java | 5 |
| 7 | kotlin/ |
Kotlin | 5 |
| 8 | cpp/ |
C++ | 5 |
| 9 | csharp/ |
C# | 5 |
| 10 | dart/ |
Dart / Flutter | 5 |
| 11 | php/ |
PHP | 5 |
| 12 | perl/ |
Perl | 5 |
| 13 | web/ |
Web 前端(HTML/CSS) | 5 |
| 14 | zh/ |
中文规则翻译 | --- |
4.2 每种语言的 5 个标准文件
每种语言目录下通常有 5 个文件,对应通用规则中的 5 个核心领域:
| 文件 | 对应通用规则 | 内容 |
|---|---|---|
coding-style.md |
common/coding-style.md |
格式化工具、惯用法、不可变实现 |
testing.md |
common/testing.md |
测试框架、覆盖率工具、测试组织 |
patterns.md |
common/patterns.md |
语言特有的设计模式 |
hooks.md |
common/hooks.md |
PostToolUse 钩子(格式化、lint) |
security.md |
common/security.md |
密钥管理、安全扫描工具 |
4.3 语言规则覆盖全景
| 通用规则 | Go | TypeScript | Python | Rust |
|---|---|---|---|---|
| 不可变性 | 指针接收器可变 | Readonly/as const | frozen dataclass | 默认不可变(增强) |
| 格式化工具 | gofmt | Prettier/ESLint | Black/Ruff | rustfmt |
| 测试框架 | go test | Jest/Vitest | pytest | cargo test |
| Lint 工具 | golangci-lint | ESLint | Ruff/Flake8 | clippy |
| 命名风格 | camelCase/PascalCase | camelCase/PascalCase | snake_case | snake_case |
| 错误处理 | 多值返回 err | try-catch + Result | try-except | Result/Option |
五、安装注意事项
5.1 目录结构必须保持
这是一个极易犯错的安装问题。再次强调:
bash
# 错误!扁平化复制会导致同名文件覆盖
cp rules/common/* ~/.claude/rules/
cp rules/golang/* ~/.claude/rules/
# 结果:golang/coding-style.md 覆盖了 common/coding-style.md
# 通用规则丢失!
# 正确!保持目录层级
cp -r rules/common ~/.claude/rules/common
cp -r rules/golang ~/.claude/rules/golang
5.2 语言规则的相对引用
语言规则文件通过相对路径引用通用规则:
markdown
> This file extends [common/coding-style.md](../common/coding-style.md)
如果扁平化复制,这个 ../common/ 路径就会失效。这是保持目录结构的另一个技术原因。
5.3 多语言项目
如果你的项目同时使用多种语言(如 TypeScript 后端 + Python ML),安装多个语言规则:
bash
cp -r rules/common ~/.claude/rules/common
cp -r rules/typescript ~/.claude/rules/typescript
cp -r rules/python ~/.claude/rules/python
Claude 会根据当前处理的文件路径(通过 paths 字段匹配)自动选择对应的语言规则。
六、为新语言添加规则
6.1 完整步骤
以添加 Ruby 规则为例:
第一步:创建目录
bash
mkdir rules/ruby
第二步:创建 5 个标准文件
每个文件以 extends 声明开头:
markdown
# rules/ruby/coding-style.md
---
paths:
- "**/*.rb"
- "**/Gemfile"
- "**/Rakefile"
---
# Ruby Coding Style
> This file extends [common/coding-style.md](../common/coding-style.md) with Ruby specific content.
## Formatting
- **RuboCop** for enforcement
- 2-space indent (Ruby community standard)
## Immutability
- Use `freeze` on string constants
- Prefer `Struct` with keyword_init for value objects
## Error Handling
- Use specific exception classes (not bare `rescue`)
- Always rescue from specific exceptions
第三步:每个文件覆盖/新增语言特有内容
| 文件 | Ruby 特有内容 |
|---|---|
coding-style.md |
RuboCop、2-space 缩进、freeze、Symbol |
testing.md |
RSpec、SimpleCov、factory_bot |
patterns.md |
Mixin、Concern、Gem 结构 |
hooks.md |
PostToolUse 运行 rubocop -A |
security.md |
Brakeman 扫描、strong_parameters |
第四步:引用相关 Skill(如果存在)
markdown
## Reference
- Skill: `ruby-patterns` --- Ruby idioms and design patterns
- Skill: `rails-testing` --- Rails-specific testing strategies
6.2 草拟模板
以下是新语言规则文件的最小模板:
markdown
---
paths:
- "**/*.<ext>"
---
# <Language> <Topic>
> This file extends [common/<topic>.md](../common/<topic>.md) with <Language> specific content.
## <Section 1: Language-specific override or addition>
## <Section 2: Tools and frameworks>
## Reference
- Skill: `<related-skill>` --- description
七、本课练习
练习 1:对比分析(15 分钟)
打开 rules/common/coding-style.md 和 rules/golang/coding-style.md,找出至少 3 个覆盖点:
bash
# 并排对比(或分两个编辑器窗口打开)
cat rules/common/coding-style.md
cat rules/golang/coding-style.md
回答:
- Go 对不可变性原则做了什么调整?
- Go 新增了哪些通用规则中没有的内容?
- 哪些通用规则 Go 没有提及(即直接继承)?
练习 2:对比 Python 和 Rust 的不可变性实现(10 分钟)
bash
cat rules/python/coding-style.md
cat rules/rust/coding-style.md
比较两种语言如何实现通用规则的"不可变性"要求:
- Python 用什么机制?(提示:
frozen=True) - Rust 用什么机制?(提示:
letvslet mut) - 哪种语言的不可变性更"强"?为什么?
练习 3:为 Ruby 草拟 coding-style.md(20 分钟)
这是本课最重要的练习。
基于你对 Ruby 的了解(如果不熟悉 Ruby,可以选择你熟悉的语言),草拟一个 rules/ruby/coding-style.md 文件。
要求:
- 以
extends声明开头 - 包含
pathsfrontmatter - 至少包含 3 个段落:Formatting、Immutability、Error Handling
- 每个段落要说明与通用规则的关系(继承/覆盖/新增)
练习 4(选做):浏览所有 14 种语言的 coding-style.md
用 10 分钟快速扫过所有语言的 coding-style.md,填写以下表格:
| 语言 | 格式化工具 | 不可变性实现 | 命名风格 |
|---|---|---|---|
| Go | |||
| TypeScript | |||
| Python | |||
| Rust | |||
| Swift | |||
| Java | |||
| ... |
八、本课小结
| 你应该记住的 | 内容 |
|---|---|
| 继承声明 | 以 > This file extends common/xxx.md 开头 |
| paths 字段 | 限定规则适用的文件路径(glob 模式) |
| 覆盖原则 | 语言 > 通用,项目 > 语言 > 通用 |
| 标准文件数 | 每种语言 5 个:coding-style / testing / patterns / hooks / security |
| 安装陷阱 | 不能扁平化复制,必须保持 common/ 和语言目录分开 |
| 新语言步骤 | 创建目录 → 5 个文件 → extends 声明 → 覆盖/新增内容 → 引用 Skill |
九、下节预告
第 6 课:Agents(上)--- 文件格式与 Frontmatter
下节课我们将深入 Agent 组件,学习 YAML frontmatter 的四个字段设计要点、description 的精确度如何影响触发效果、tools 的最小权限原则,以及 model 的选择策略。
预习建议 :打开 10 个不同的 Agent 文件,对比它们的 frontmatter 差异,特别注意 tools 和 model 的组合模式。