函数拆分ã€ä½œç”¨åŸŸä¸Žå¤ç”¨
这一周é‡ç‚¹æ˜¯æŠŠç¨‹åºæ‹†å¼€åŽä»ç„¶å¯ç»´æŠ¤ã€‚ä½ ä¼šç»ƒå‡½æ•°æ‹†åˆ†ã€å˜é‡ä½œç”¨åŸŸå’Œå¼•ç”¨ä¼ å‚,让代ç 从“能跑â€è¿›é˜¶åˆ°â€œèƒ½é•¿æœŸç»´æŠ¤â€ã€‚
å¦å®Œè¿™å‘¨ï¼Œä½ 能判æ–什么时候用局部å˜é‡ï¼Œä»€ä¹ˆæ—¶å€™è¯¥ç”¨å¼•ç”¨å‚æ•°ï¼Œä»¥åŠæ€Žä¹ˆé¿å…作用域冲çªã€‚
7.1 函数拆分ç–ç•¥
先列主æµç¨‹ï¼Œå†æŒ‰èŒè´£æ‹†å‡½æ•°ï¼šè¾“å…¥ã€å¤„ç†ã€è¾“出。一个函数尽é‡åªåšä¸€ä»¶äº‹ï¼Œè¿™æ ·æ”¹åŠ¨éœ€æ±‚æ—¶ä¸å®¹æ˜“牵连全局。
7.2 å˜é‡ä½œç”¨åŸŸ
局部å˜é‡åªåœ¨å¯¹åº”函数或代ç å—内有效。作用域混乱会导致“å˜é‡æœªå®šä¹‰â€æˆ–“误用旧值â€é—®é¢˜ã€‚
void demo() {
int x = 10;
if (x > 5) {
int y = x * 2;
cout << y << "\n";
}
// cout << y; // y 在这里ä¸å¯ç”¨
}
7.3 å¼•ç”¨ä¼ å‚与 const 引用
需è¦ä¿®æ”¹å¤–部å˜é‡æ—¶ç”¨å¼•ç”¨å‚æ•° `&`,åªè¯»åœºæ™¯ä¼˜å…ˆ `const &`ï¼Œè¿™æ ·æ—¢æ¸…æ™°åˆé«˜æ•ˆã€‚
void addBonus(int& score, int bonus) {
score += bonus;
}
int calcTotal(const vector<int>& scores) {
int sum = 0;
for (int s : scores) sum += s;
return sum;
}
7.4 æ·±åº¦è®²è§£ï¼šä½œç”¨åŸŸé”™è¯¯ä¸ºä»€ä¹ˆæ€»åœ¨é‡æž„åŽçˆ†å‘
很多åŒå¦ä¼šå‘现:代ç 刚写完时能跑,拆函数åŽå而报错。常è§åŽŸå› å°±æ˜¯ä½œç”¨åŸŸç†è§£ä¸å®Œæ•´ã€‚å˜é‡åœ¨å‡½æ•°é‡Œå®šä¹‰ï¼Œåªåœ¨è¯¥å‡½æ•°æœ‰æ•ˆï¼›å˜é‡åœ¨ `if` 或 `for` 代ç å—里定义,åªåœ¨é‚£ä¸ªå—å†…æœ‰æ•ˆã€‚é‡æž„æ—¶ä½ æŠŠä»£ç 移动ä½ç½®åŽï¼ŒåŽŸæ¥çš„å˜é‡å¯èƒ½å·²ç»è¶…å‡ºä½œç”¨åŸŸï¼Œå¯¼è‡´â€œæœªå®šä¹‰æ ‡è¯†ç¬¦â€æˆ–“读到错误旧值â€ã€‚è¿™ä¸æ˜¯ä½ å†™å¾—å·®ï¼Œè€Œæ˜¯è¯´æ˜Žä½ æ£åœ¨è¿›å…¥æ›´çœŸå®žçš„工程阶段:代ç ä½ç½®å˜åŒ–会影å“å¯è§æ€§ã€‚
解决æ€è·¯æ˜¯å…ˆç”»â€œæ•°æ®æµå›¾â€ï¼šè¿™ä¸ªå˜é‡åœ¨å“ªé‡Œåˆ›å»ºï¼Ÿè°è´Ÿè´£æ›´æ–°ï¼Ÿè°è´Ÿè´£è¯»å–?什么时候失效?åªè¦è¿™å››ä¸ªé—®é¢˜æ¸…楚,作用域问题基本都能æå‰é¿å…ã€‚ä½ å¯ä»¥æŠŠâ€œåˆ›å»ºå˜é‡â€çš„ä½ç½®å°½é‡é 近使用点,å‡å°‘生命周期;也è¦é¿å…æŠŠå¤§é‡æ— å…³å˜é‡æ”¾åœ¨å‡½æ•°æœ€ä¸Šé¢ï¼Œè¿™ä¼šå¢žåŠ è¯¯ç”¨é£Žé™©ã€‚å±€éƒ¨å˜é‡å¹¶ä¸æ˜¯è¶Šå°‘越好,而是“有效范围越å°è¶Šå®‰å…¨â€ã€‚
å¦ä¸€ä¸ªé«˜é¢‘呿˜¯é‡åå˜é‡ï¼ˆshadowing)。例如函数外有 `int score`,函数内åˆå®šä¹‰äº† `int score`ï¼Œä½ ä»¥ä¸ºåœ¨ä¿®æ”¹åŒä¸€ä¸ªå€¼ï¼Œå®žé™…上改的是å¦ä¸€ä¸ªå±€éƒ¨å˜é‡ã€‚为了é¿å…è¿™ç§éšè”½é”™è¯¯ï¼Œå»ºè®®åœ¨é‡æž„阶段使用更明确命å,例如 `currentScore`ã€`inputScore`ã€`totalScore`ã€‚å‘½åæ¸…æ™°åŽï¼Œä½ 的大脑负担会明显å‡è½»ã€‚
7.5 æ·±åº¦è®²è§£ï¼šå¼•ç”¨ä¼ å‚与副作用控制
å¼•ç”¨ä¼ å‚ `&` å¾ˆå¼ºå¤§ï¼Œå› ä¸ºå®ƒå…许函数直接修改外部å˜é‡ã€‚但“强大â€ä¹Ÿæ„味ç€â€œæ›´å®¹æ˜“出副作用â€ã€‚副作用指的是:调用者看起æ¥åªæ˜¯è°ƒç”¨äº†å‡½æ•°ï¼Œå´ä¸æ¸…楚函数悄悄改了哪些数æ®ã€‚副作用过多会让程åºè¡Œä¸ºå˜å¾—éš¾ä»¥é¢„æµ‹ã€‚å»ºè®®ä½ æŠŠâ€œä¼šä¿®æ”¹å¤–éƒ¨æ•°æ®â€çš„函数在命å上明确表达出æ¥ï¼Œæ¯”如 `updateScore`ã€`appendTask`,让调用者一眼有心ç†é¢„期。
对于åªè¯»åœºæ™¯ï¼Œä¼˜å…ˆä½¿ç”¨ `const &`ã€‚è¿™æ ·æ—¢èƒ½é¿å…æ‹·è´ï¼Œåˆèƒ½é˜²æ¢è¯¯æ”¹æ•°æ®ã€‚例如 `void printTasks(const vector<Task>& tasks)` 明确告诉读者:这个函数åªè¯»ä¸æ”¹ã€‚å…»æˆè¿™ä¸ªä¹ 惯åŽï¼Œä½ 会自动形æˆâ€œæŽ¥å£å¥‘çº¦â€æ€ç»´ï¼šå‡½æ•°è¾“入输出边界是清楚且å¯ä¿¡çš„。åŽç»å¤šäººå作时,这ç§å¥‘约æ€ç»´æ¯”写代ç 速度更é‡è¦ã€‚
å½“ä½ ä¸ç¡®å®šæ˜¯å¦è¯¥ç”¨å¼•用时,å¯ä»¥å…ˆç”¨å€¼ä¼ 递写通逻辑,å†è¯„ä¼°æ€§èƒ½å’Œä¿®æ”¹éœ€æ±‚ã€‚å¦‚æžœå‡½æ•°ç¡®å®žéœ€è¦æŠŠç»“æžœå›žä¼ ç»™è°ƒç”¨æ–¹ï¼Œå†æ”¹ä¸ºå¼•ç”¨å‚æ•°ã€‚è¿™æ ·åšèƒ½é™ä½Žä¸€æ¬¡æ€§è®¾è®¡è¿‡åº¦å¸¦æ¥çš„夿‚度。å¦ä¹ 阶段é‡ç‚¹ä¸æ˜¯â€œå†™å‡ºæœ€ç‚«çš„è¯æ³•â€ï¼Œè€Œæ˜¯å†™å‡ºè¡Œä¸ºå¯é¢„测ã€å¯è§£é‡Šçš„代ç 。
void markDoneById(vector<Task>& tasks, int id) {
for (Task& t : tasks) {
if (t.id == id) {
t.done = true;
return;
}
}
}
void printTasks(const vector<Task>& tasks) {
for (const Task& t : tasks) {
cout << t.id << " " << t.title << " " << t.done << "\n";
}
}
7.6 釿ž„å®žæˆ˜ï¼šä»Žé•¿å‡½æ•°åˆ°æ¨¡å—æµç¨‹
æœ¬å‘¨å»ºè®®ä½ åšä¸€æ¬¡å®Œæ•´é‡æž„演练。å‡è®¾ä½ 有一个 150 行的任务管ç†ç¨‹åºï¼Œå…ˆä¸è¦æ€¥ç€â€œç¾ŽåŒ–代ç â€ï¼Œå…ˆåšç»“构拆分:èœå•展示ã€è¾“入处ç†ã€ä¸šåŠ¡é€»è¾‘ã€ç»“果输出分别独立。然åŽé€ä¸ªæ›¿æ¢æ—§æµç¨‹ï¼Œæ¯æ›¿æ¢ä¸€æ¥å°±è¿è¡Œä¸€æ¬¡æµ‹è¯•。这个节å¥å«â€œå°æ¥é‡æž„â€ï¼Œå®ƒèƒ½è®©ä½ å§‹ç»ˆä¿æŒå¯è¿è¡Œçжæ€ï¼Œå‡ºé”™æ—¶ä¹Ÿèƒ½è¿…速回退。
釿ž„时最容易忽视的是“行为一致性â€ã€‚ä½ æ”¹å®Œç»“æž„åŽï¼ŒåŠŸèƒ½æ˜¯å¦ä¸Žæ—§ç‰ˆæœ¬å®Œå…¨ä¸€è‡´ï¼Ÿæœ€ç¨³å¦¥çš„åŠžæ³•æ˜¯å‡†å¤‡å›ºå®šæµ‹è¯•é›†ï¼Œé‡æž„å‰åŽéƒ½è·‘一é,比较输出。åªè¦ç»“æžœä¸€è‡´ï¼Œä½ å°±èƒ½ç¡®è®¤æœ¬æ¬¡é‡æž„是安全的。请记ä½ï¼šé‡æž„çš„ç›®æ ‡æ˜¯æå‡ç»“构质é‡ï¼Œä¸æ˜¯å·å·æ”¹å˜ä¸šåŠ¡è§„åˆ™ã€‚å¾ˆå¤šé¡¹ç›®çº¿ä¸Šäº‹æ•…éƒ½æ¥è‡ªâ€œé‡æž„é¡ºæ‰‹æ”¹äº†é€»è¾‘å´æ²¡æµ‹è¯•â€ã€‚
å½“ä½ å®Œæˆä¸€æ¬¡é«˜è´¨é‡é‡æž„ï¼Œä½ ä¼šæ˜Žæ˜¾æ„Ÿåˆ°ä¸¤ä¸ªå˜åŒ–:第一,新增功能ä¸å†ç‰µä¸€å‘而动全身;第二,调试速度å˜å¿«ï¼Œå› 为æ¯ä¸ªå‡½æ•°è¾¹ç•Œæ¸…晰。第7周的æ„ä¹‰å°±åœ¨è¿™é‡Œï¼šä½ å¼€å§‹çœŸæ£å…·å¤‡â€œç»´æŠ¤ä»£ç â€çš„能力,而ä¸åªæ˜¯â€œå†™ä¸€æ®µèƒ½è·‘的代ç â€ã€‚
7.7 è¯¾å ‚é—®ç”与进阶练ä¹
é—®ï¼šé‡æž„时我最怕“改å原功能â€ï¼Œæ€Žä¹ˆåŠžï¼Ÿ 用“冻结行为â€ç–略:先记录旧版本输入输出,å†å¼€å§‹é‡æž„。æ¯é‡æž„䏀尿¥ï¼Œå°±è·‘åŒä¸€ç»„测试对比结果。åªè¦ç»“æžœä¸€è‡´ï¼Œè¯´æ˜Žä½ åœ¨æ”¹ç»“æž„è€Œä¸æ˜¯æ”¹ä¸šåŠ¡ã€‚è¿™ä¸ªæ–¹æ³•æ¯”å‡æ„Ÿè§‰å®‰å…¨å¾—多,也更符åˆçœŸå®žå›¢é˜Ÿå¼€å‘æµç¨‹ã€‚
问:什么时候应该把å˜é‡æå‡åˆ°å‡½æ•°å¤–? åªæœ‰åœ¨ç¡®å®žéœ€è¦è·¨å‡½æ•°å…±äº«ã€å¹¶ä¸”å…±äº«èŒƒå›´å¯æŽ§æ—¶æ‰è€ƒè™‘。默认优先局部å˜é‡ï¼Œè®©ç”Ÿå‘½å‘¨æœŸå°½é‡çŸã€‚范围越å°ï¼Œå‰¯ä½œç”¨è¶Šå°‘ï¼›èŒƒå›´è¶Šå¤§ï¼ŒæŽ’é”™è¶Šéš¾ã€‚ä½ å¯ä»¥æŠŠâ€œèƒ½å±€éƒ¨å°±ä¸å…¨å±€â€å½“æˆé»˜è®¤ç–ç•¥ï¼Œé™¤éžæœ‰æ˜Žç¡®ç†ç”±æ‰“ç ´ã€‚
é—®ï¼šå¼•ç”¨ä¼ å‚æ˜¯ä¸æ˜¯ä¸€å®šæ¯”å€¼ä¼ é€’å¥½ï¼Ÿ ä¸ä¸€å®šã€‚对å°ç±»åž‹ï¼ˆå¦‚ `int`ã€`double`ï¼‰å€¼ä¼ é€’å·²ç»è¶³å¤Ÿï¼Œä»£ç 也更直观。对大对象(如 `vector`ã€`string`)æ‰ä¼˜å…ˆè€ƒè™‘ `const &`。如果函数è¦ä¿®æ”¹å¤–部对象,å†ç”¨éžå¸¸é‡å¼•ç”¨ã€‚é€‰æ‹©ä¾æ®æ˜¯â€œè¯ä¹‰ + æˆæœ¬â€ï¼Œè€Œä¸æ˜¯ç»Ÿä¸€å¥—模æ¿ã€‚
è¿›é˜¶ç»ƒä¹ å»ºè®®ï¼šæŠŠâ€œä»»åŠ¡æ¸…å•ç¨‹åº v2â€ç»§ç»å‡çº§ä¸ºâ€œä»»åŠ¡æ¸…å•ç¨‹åº v3â€ã€‚è¦æ±‚: ç¬¬ä¸€ï¼Œæ–°å¢žâ€œæŒ‰å…³é”®å—æœç´¢ä»»åŠ¡â€ï¼› 第二,新增“导出已完æˆä»»åŠ¡åˆ—è¡¨â€ï¼› 第三,所有数æ®ä¿®æ”¹æ“作都通过独立函数完æˆï¼› 第四,写出模å—边界说明:哪些函数属于输入层ã€å“ªäº›å±žäºŽä¸šåС层ã€å“ªäº›å±žäºŽè¾“出层。 è¿™ä¸ªç»ƒä¹ èƒ½å¼ºè¿«ä½ çœŸæ£æ‰§è¡Œåˆ†å±‚ï¼Œè€Œä¸æ˜¯å£å¤´åˆ†å±‚。
完æˆåŽåšä¸€æ¬¡å¤ç›˜ç”辩:用 3 åˆ†é’Ÿè®²æ¸…ä½ çš„æ¨¡å—ç»“æž„ã€æ•°æ®æµå‘ã€æµ‹è¯•ç–略和已知é™åˆ¶ã€‚能讲清楚,æ‰è¯´æ˜Žä½ 真的掌æ¡äº†é‡æž„æ€ç»´ã€‚第7å‘¨çš„ç›®æ ‡ä¸æ˜¯â€œä»£ç 行数更多â€ï¼Œè€Œæ˜¯â€œç³»ç»Ÿç»“构更清楚â€ã€‚
7.8 æœ¬å‘¨ç»ƒä¹ ä¸Žè‡ªæµ‹æ¸…å•
本周练ä¹
- 把旧程åºé‡æž„æˆè‡³å°‘ 5 个函数。
- 至少 2 个函数使用 `const &` ä¼ å‚。
- 补一份函数èŒè´£è¯´æ˜Žã€‚
自测清å•
- å˜é‡ä½œç”¨åŸŸæ˜¯å¦æ¸…æ™°ã€æ— 越界访问。
- å‡½æ•°æŽ¥å£æ˜¯å¦ç»Ÿä¸€ã€å‘½å是å¦ä¸€è‡´ã€‚
- 釿ž„åŽåŠŸèƒ½æ˜¯å¦ä¸Žé‡æž„å‰ä¸€è‡´ã€‚
- ä»£ç æ˜¯å¦æ¯”釿ž„剿›´æ˜“读。
è¡¥å……å»ºè®®ï¼šæŠŠæœ¬å‘¨é‡æž„è¿‡ç¨‹æ•´ç†æˆâ€œæ”¹åŠ¨æ—¥å¿—â€ï¼Œè‡³å°‘记录 5 个关键决ç–点。未æ¥ä½ 会å‘çŽ°ï¼Œè¿™ä»½æ—¥å¿—æ¯”ä»£ç æœ¬èº«æ›´èƒ½å¸®åŠ©ä½ å¿«é€Ÿå›žå¿†è®¾è®¡æ€è·¯ã€‚