ฉันคิดว่า @JackAidley พูดถึงแก่นสารของมันมาแล้วแต่ให้ฉันกำหนดเช่นนี้:
โดยไม่มีข้อยกเว้น (เช่น C)
ในโฟลว์โค้ดปกติคุณมี:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
ในกรณี“ ผิดพลาดเร็ว” รหัสของคุณก็จะอ่าน:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
หากคุณพบรูปแบบนี้ - return
ในelse
(หรือแม้กระทั่งif
) บล็อกการทำงานซ้ำได้ทันทีเพื่อให้รหัสในคำถามที่ไม่ได้มีการelse
บล็อก:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
ในโลกแห่งความจริง ...
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
วิธีนี้จะหลีกเลี่ยงการวางซ้อนลึกเกินไปและตอบสนองกรณี“ แตกออกเร็ว” (ช่วยรักษาความคิด - และการไหลของรหัส - สะอาด) และไม่ละเมิด "ใส่สิ่งที่มีโอกาสมากขึ้นในif
ส่วน" เพราะไม่มีelse
ส่วนใด ๆ.
C
และทำความสะอาด
ได้รับแรงบันดาลใจจากคำตอบของคำถามที่คล้ายกัน (ซึ่งผิดพลาด) นี่คือวิธีที่คุณทำความสะอาดด้วย C คุณสามารถใช้จุดทางออกหนึ่งหรือสองจุดตรงนี้คือจุดหนึ่งสำหรับจุดทางออกสองจุด:
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
คุณสามารถยุบออกเป็นจุดเดียวหากมีการล้างข้อมูลน้อยกว่า:
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
การใช้งานgoto
นี้ดีมากหากคุณสามารถจัดการกับมันได้ คำแนะนำในการที่จะเข้าออกโดยใช้goto
เป็นผู้กำกับที่คนที่ยังไม่สามารถตัดสินใจได้ด้วยตัวเองไม่ว่าจะเป็นการใช้งานเป็นสิ่งที่ดีที่ยอมรับไม่ดีรหัสปาเก็ตตี้หรือสิ่งอื่น
ข้อยกเว้น
การพูดถึงข้างต้นเกี่ยวกับภาษาโดยไม่มีข้อยกเว้นซึ่งฉันชอบตัวเองเป็นอย่างมาก (ฉันสามารถใช้ข้อผิดพลาดอย่างชัดเจนในการจัดการที่ดีกว่ามากและด้วยความประหลาดใจน้อยกว่า) ในการอ้าง igli:
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
แต่นี่คือคำแนะนำว่าคุณทำได้ดีในภาษาที่มีข้อยกเว้นและเมื่อคุณต้องการใช้งานได้ดี:
เกิดข้อผิดพลาดในการเผชิญกับข้อยกเว้น
คุณสามารถแทนที่ต้นส่วนใหญ่return
ด้วยการโยนข้อยกเว้น อย่างไรก็ตามการไหลของโปรแกรมปกติของคุณคือการไหลของรหัสใด ๆ ที่โปรแกรมไม่พบข้อยกเว้น ... เงื่อนไขข้อผิดพลาดหรือบางประการจะไม่เพิ่มข้อยกเว้นใด ๆ
ซึ่งหมายความว่า ...
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
…ไม่เป็นไร แต่…
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… ไม่ใช่. โดยทั่วไปมีข้อยกเว้นไม่ได้เป็นองค์ประกอบการควบคุมการไหล สิ่งนี้ยังทำให้การดำเนินการดูแปลก ๆ ที่คุณ (“ โปรแกรมเมอร์ Java ™เหล่านั้นมักจะบอกเราว่าข้อยกเว้นเหล่านี้เป็นเรื่องปกติ”) และสามารถขัดขวางการแก้ไขข้อบกพร่อง (เช่นบอก IDE ว่าเพียงแค่ผิดพลาด) ข้อยกเว้นมักต้องการสภาพแวดล้อมรันไทม์เพื่อคลายสแต็กเพื่อสร้างการติดตามย้อนกลับ ฯลฯ อาจมีเหตุผลมากกว่านั้น
สิ่งนี้จะลดลงไปถึง: ในภาษาที่รองรับข้อยกเว้นใช้สิ่งที่ตรงกับตรรกะและสไตล์ที่มีอยู่และให้ความรู้สึกเป็นธรรมชาติ หากเขียนอะไรตั้งแต่เริ่มต้นให้ขอความเห็นด้วยก่อนเวลา หากเขียนห้องสมุดตั้งแต่เริ่มต้นให้นึกถึงผู้บริโภคของคุณ (ไม่เคยใช้abort()
ในห้องสมุดอย่างใดอย่างหนึ่ง ... ) แต่สิ่งที่คุณทำไม่ได้เป็นข้อยกเว้นถ้าการดำเนินการต่อไป (มากหรือน้อย) ตามปกติหลังจากนั้น
คำแนะนำทั่วไป ข้อยกเว้น
พยายามใช้การยกเว้นทั้งหมดที่อยู่ในโปรแกรมที่ตกลงกันโดยทั้งทีม dev ก่อน โดยทั่วไปวางแผนพวกเขา อย่าใช้พวกเขาในความอุดมสมบูรณ์ บางครั้งแม้ใน C ++, Java ™, Python การส่งคืนข้อผิดพลาดจะดีกว่า บางครั้งมันไม่ได้; ใช้พวกเขาด้วยความคิด