第 5 课:Rules(下)— 语言特定规则与实战

所属阶段:第二阶段「组件精讲」(第 4-15 课) 前置条件:第 4 课 本课收获:能对比通用与语言规则的差异,能为新语言草拟规则


一、本课概述

上节课我们学习了 10 个通用规则文件。这节课进入语言特定规则层:

  1. 继承机制 --- 语言规则如何"继承并覆盖"通用规则
  2. 覆盖案例 --- 真实的继承覆盖场景分析
  3. 14 种语言的规则结构 --- 每种语言通常有 5 个文件
  4. 添加新语言 --- 从零开始为一种新语言创建规则

这节课是 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 mutCow)。

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.mdrules/golang/coding-style.md,找出至少 3 个覆盖点:

bash 复制代码
# 并排对比(或分两个编辑器窗口打开)
cat rules/common/coding-style.md
cat rules/golang/coding-style.md

回答:

  1. Go 对不可变性原则做了什么调整?
  2. Go 新增了哪些通用规则中没有的内容?
  3. 哪些通用规则 Go 没有提及(即直接继承)?

练习 2:对比 Python 和 Rust 的不可变性实现(10 分钟)

bash 复制代码
cat rules/python/coding-style.md
cat rules/rust/coding-style.md

比较两种语言如何实现通用规则的"不可变性"要求:

  • Python 用什么机制?(提示:frozen=True
  • Rust 用什么机制?(提示:let vs let mut
  • 哪种语言的不可变性更"强"?为什么?

练习 3:为 Ruby 草拟 coding-style.md(20 分钟)

这是本课最重要的练习。

基于你对 Ruby 的了解(如果不熟悉 Ruby,可以选择你熟悉的语言),草拟一个 rules/ruby/coding-style.md 文件。

要求:

  • extends 声明开头
  • 包含 paths frontmatter
  • 至少包含 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 差异,特别注意 toolsmodel 的组合模式。

相关推荐
王小酱2 小时前
第 6 课:Agents(上)— 文件格式与 Frontmatter
openai·ai编程·aiops
王小酱2 小时前
第 3 课:上手体验 — 安装与目录漫游
openai·ai编程·aiops
王小酱2 小时前
第 9 课:Skills(下)— 编程 Skill 地图与编写实战
openai·ai编程·aiops
王小酱2 小时前
第 7 课:Agents(下)— 系统提示词设计
openai·ai编程·aiops
孟健2 小时前
对不起,OpenClaw,我选择 Hermes!
ai编程
王小酱2 小时前
第 1 课:设计哲学 — ECC 为什么存在
openai·ai编程·aiops
Bigger2 小时前
CodeWalkers:让 AI 助手化身桌面宠物,陪你敲代码的赛博伙伴!
前端·app·ai编程
王小酱2 小时前
Everything Claude Code 三十节课程大纲
openai·ai编程·aiops
王小酱2 小时前
第 2 课:架构全景 — 六大组件如何协作
openai·ai编程·aiops