ทำไมต้องใช้คำเตือนและคำเตือนที่เข้มงวด?


105

สำหรับฉันแล้วดูเหมือนว่าคำถามหลายข้อในแท็ก Perl สามารถแก้ไขได้หากผู้คนใช้:

use strict;
use warnings;

ฉันคิดว่าบางคนคิดว่าสิ่งเหล่านี้คล้ายกับวงล้อฝึกหัดหรือภาวะแทรกซ้อนที่ไม่จำเป็นซึ่งไม่เป็นความจริงอย่างชัดเจนเนื่องจากแม้แต่โปรแกรมเมอร์ Perl ที่มีทักษะสูงก็ใช้มัน

ดูเหมือนว่าคนส่วนใหญ่ที่มีความเชี่ยวชาญใน Perl มักจะใช้ pragmas ทั้งสองนี้ในขณะที่ผู้ที่จะได้รับประโยชน์สูงสุดจากการใช้พวกเขาแทบจะไม่ทำ ดังนั้นผมคิดว่ามันจะเป็นความคิดที่ดีที่จะมีคำถามที่จะเชื่อมโยงไปยังเมื่อกระตุ้นให้ประชาชนและuse strictwarnings

เหตุใดนักพัฒนา Perl จึงควรuse strictและwarnings?


14
ฉันมักจะสงสัยว่าทำไมพวกเขาไม่เพียง แต่ทำให้มันเป็นค่าเริ่มต้นและมีนักพัฒนาจริง ๆ ที่ต้องคลายสิ่งต่าง ๆ อยู่ที่ไหนuse loose;
Paul Tyng

12
เช่นเดียวกับสิ่งที่เจ๋งและมีประโยชน์มากมาย Perl เริ่มต้นจากการแฮ็กเป็นเครื่องมือสำหรับคนที่คิดค้นมันขึ้นมา ต่อมาได้รับความนิยมมากขึ้นและมีคนไม่ชำนาญเพิ่มมากขึ้นเริ่มใช้มัน นี่คือตอนที่คุณเริ่มคิดว่าuse strictเป็นความคิดที่ดี แต่ความเข้ากันได้แบบย้อนกลับได้กลายเป็นปัญหาที่แท้จริงสำหรับคุณ :-(
Daniel Böhmer

14
@JB Nizet, @Paul T. ที่จริงแล้วuse strict;จะเปิดโดยค่าเริ่มต้นเมื่อคุณขอภาษา Perl 5.12 (หรือสูงกว่า) ลองperl -e"use v5.012; $x=123;". no strict;จริงๆแล้วจะปิด
ikegami

1
แม้ว่าท้ายที่สุดแล้วประเด็นของคุณจะเป็นความจริง แต่ยิ่งเราพูดบ่อยเท่าไหร่คนก็จะยิ่งได้ยินมากขึ้นเท่านั้น เมื่อไม่นานมานี้มีเสียงดังก้องในการพยายามสร้างบทช่วยสอน Perl ให้มากขึ้น / ดีขึ้น / ทันสมัยและคำเตือนที่เข้มงวด / คำเตือนจะอยู่ด้านบนของแต่ละข้อ สำหรับของฉันฉันวางแผนที่จะมี s / w อยู่ด้านบนของทุกตัวอย่างเพื่อให้มือใหม่ทุกคนเห็นทุกครั้ง
Joel Berger

5
@JoelBerger ไม่จริงมันไม่มีอะไรเหมือนเลย อย่างที่ฉันพูดมันมีแค่คำที่คล้ายกันในชื่อเรื่อง สำหรับความเข้ากันได้ย้อนหลัง เป็นประโยคแรกในคำตอบที่ยอมรับคุณจะเสนอสิ่งนั้นกับคำถามของฉันได้อย่างไร
TLP

คำตอบ:


84

สำหรับผู้เริ่มต้นuse strict;(และในระดับที่น้อยกว่าuse warnings;) ช่วยค้นหาการพิมพ์ผิดในชื่อตัวแปร แม้แต่โปรแกรมเมอร์ที่มีประสบการณ์ก็ยังทำข้อผิดพลาดดังกล่าว กรณีทั่วไปคือลืมเปลี่ยนชื่ออินสแตนซ์ของตัวแปรเมื่อล้างข้อมูลหรือปรับโครงสร้างโค้ดใหม่

การใช้การuse strict; use warnings;จับข้อผิดพลาดจำนวนมากเร็วกว่าที่จะถูกจับได้ซึ่งทำให้ง่ายต่อการค้นหาสาเหตุของข้อผิดพลาด สาเหตุที่แท้จริงอาจเป็นความจำเป็นในการตรวจสอบข้อผิดพลาดหรือการตรวจสอบความถูกต้องและอาจเกิดขึ้นได้โดยไม่คำนึงถึงทักษะของโปรแกรมเมอร์หรือ

สิ่งที่ดีเกี่ยวกับคำเตือนของ Perl คือไม่ค่อยมีการปลอมแปลงดังนั้นจึงไม่มีค่าใช้จ่ายในการใช้


การอ่านที่เกี่ยวข้อง: ทำไมต้องใช้my?


2
@TLP ฉันไม่ได้กำลังจะทำการศึกษาเพื่อหาปริมาณว่ามันช่วยได้มากแค่ไหน ควรพอเพียงที่จะบอกว่าพวกเขาช่วยโดยไม่มีเงื่อนไข
ikegami

1
ทำไมถึงทำเป็นทางเลือกถ้ามันมีประโยชน์มากมาย? ทำไมไม่เปิดใช้งานตามค่าเริ่มต้น (เหมือนที่มีคนแสดงความคิดเห็นไว้ข้างบน) เป็นเพราะเหตุผลด้านความเข้ากันได้หรือไม่?
ฌอง

4
@Jean ความเข้ากันได้ย้อนหลัง โปรดทราบว่าuse strict;จะเปิดใช้งานโดยค่าเริ่มต้นหากคุณใช้ภาษาเวอร์ชัน 5.12 หรือใหม่กว่า ( use 5.012;)
ikegami

@Jean หากคุณกำลังเขียนสคริปต์ง่ายๆคุณไม่ต้องการรับการแจ้งเตือนจากคำเตือนเกี่ยวกับชื่อตัวจัดการไฟล์หรือไม่ได้ประกาศตัวแปรก่อนใช้ :-)
user2676847

28

เห็นได้ชัดว่าuse strictควร (ต้อง) ใช้เมื่อคุณต้องการบังคับให้ perl เขียนโค้ดอย่างถูกต้องซึ่งอาจเป็นการบังคับให้มีการประกาศโดยมีความชัดเจนเกี่ยวกับสตริงและส่วนย่อยเช่น barewords หรือใช้การอ้างอิงด้วยความระมัดระวัง หมายเหตุ: หากมีข้อผิดพลาดให้ใช้อย่างเข้มงวดจะยกเลิกการดำเนินการหากใช้

แม้ว่าuse warnings;จะช่วยให้คุณพบข้อผิดพลาดในการพิมพ์ในโปรแกรมเช่นคุณพลาดอัฒภาค แต่คุณใช้ "elseif" ไม่ใช่ "elsif" แต่คุณกำลังใช้ไวยากรณ์หรือฟังก์ชันที่เลิกใช้แล้วไม่ว่าจะอย่างนั้นก็ตาม หมายเหตุ: คำเตือนการใช้งานจะให้คำเตือนและดำเนินการต่อเช่นจะไม่ยกเลิกการดำเนินการ ..

อย่างไรก็ตามมันจะดีกว่าถ้าเราลงรายละเอียดซึ่งฉันระบุไว้ด้านล่าง

จากperl.com (รายการโปรด):

ใช้ 'vars' ที่เข้มงวด

ซึ่งหมายความว่าคุณต้องประกาศตัวแปรก่อนที่จะใช้เสมอ

หากคุณไม่ประกาศคุณอาจได้รับข้อความแสดงข้อผิดพลาดสำหรับตัวแปรที่ไม่ได้ประกาศ

สัญลักษณ์ส่วนกลาง "$ variablename" ต้องการชื่อแพ็กเกจที่ชัดเจนที่ scriptname.pl บรรทัดที่ 3

คำเตือนนี้หมายความว่า Perl ไม่ชัดเจนว่าขอบเขตของตัวแปรคืออะไร ดังนั้นคุณต้องมีความชัดเจนเกี่ยวกับตัวแปรของคุณซึ่งหมายถึงการประกาศตัวแปรเหล่านี้ด้วยmyเพื่อให้ถูก จำกัด ไว้ที่บล็อกปัจจุบันหรืออ้างอิงถึงตัวแปรด้วยชื่อที่มีคุณสมบัติครบถ้วน (เช่น: $ MAIN :: variablename)

ดังนั้นข้อผิดพลาดเวลาคอมไพล์จะถูกทริกเกอร์หากคุณพยายามเข้าถึงตัวแปรที่ไม่ตรงตามเกณฑ์อย่างน้อยหนึ่งข้อต่อไปนี้:

  • กำหนดไว้ล่วงหน้าโดย Perl เองเช่น @ARGV,% ENV และตัวแปรเครื่องหมายวรรคตอนทั้งหมดเช่น $ หรือ $ _.

  • ประกาศด้วย (สำหรับทั่วโลก) หรือของฉัน (สำหรับคำศัพท์)

  • นำเข้าจากแพ็คเกจอื่น (การใช้ vars pragma ปลอมการนำเข้า แต่ใช้ของเราแทน)

  • มีคุณสมบัติครบถ้วนโดยใช้ชื่อแพ็กเกจและตัวคั่นแพ็กเกจ double-colon

ใช้ 'subs' ที่เข้มงวด

พิจารณาสองโปรแกรม

# prog 1
   $a = test_value;
   print "First program: ", $a, "\n";
   sub test_value { return "test passed"; }
 Output: First program's result: test_value

# prog 2
   sub test_value { return "test passed"; }
   $a = test_value;
   print "Second program: ", $a, "\n";
 Output: Second program's result: test passed

ในทั้งสองกรณีเรามีค่าย่อย test_value () และเราต้องการใส่ผลลัพธ์เป็น $ a และเมื่อเราเรียกใช้ทั้งสองโปรแกรมเราจะได้ผลลัพธ์ที่แตกต่างกันสองรายการ:

ในโปรแกรมแรก ณ จุดที่เราไปถึง$a = test_value;Perl จะไม่ทราบถึง test_value () ย่อยใด ๆ และ test_value จะตีความเป็นสตริง 'test_value' ในโปรแกรมที่สองนิยามของ test_value () จะอยู่ก่อน$a = test_value;บรรทัด Perl คิดว่า test_value เป็นการเรียกย่อย

ระยะทางเทคนิคสำหรับคำที่แยกได้เช่น test_value ที่อาจจะมีผู้ใต้บังคับบัญชาและอาจจะเป็นสตริงขึ้นอยู่กับบริบทโดยวิธีการที่เป็นbareword การจัดการBarewordsของ Perl อาจทำให้เกิดความสับสนและอาจทำให้เกิดข้อผิดพลาดในโปรแกรม

จุดบกพร่องคือสิ่งที่เราพบในโปรแกรมแรกของเราโปรดจำไว้ว่า Perl จะไม่รอคอยที่จะพบtest_value()ดังนั้นเนื่องจากยังไม่เห็น test_value () จึงถือว่าคุณต้องการสตริง ดังนั้นถ้าคุณuse strict subs;มันจะทำให้โปรแกรมนี้ตายด้วยข้อผิดพลาด:

ไม่อนุญาตให้ใช้ Bareword "test_value" ในขณะที่ใช้ "กลุ่มย่อยที่เข้มงวด" ที่ ./a6-strictsubs.pl บรรทัดที่ 3

วิธีแก้ไขข้อผิดพลาดนี้คือ
1. ใช้วงเล็บเพื่อให้ชัดเจนว่าคุณกำลังเรียกหน่วยย่อย หาก Perl เห็น $ a = test_value ();
2. ประกาศย่อยของคุณก่อนใช้งานครั้งแรก

use strict;
sub test_value;  # Declares that there's a test_value() coming later ...
my $a = test_value;  # ...so Perl will know this line is okay.
.......
sub test_value { return "test_passed"; }

3. และหากคุณต้องการใช้เป็นสตริงให้อ้าง

ดังนั้นการเข้มงวดนี้ทำให้ Perl ถือว่า barewords ทั้งหมดเป็นข้อผิดพลาดทางไวยากรณ์ A * barewordเป็นชื่อเปลือยใด ๆ หรือระบุว่าไม่เคยมีใครตีความอื่น ๆ บังคับโดยบริบท (บริบทมักถูกบังคับโดยคีย์เวิร์ดหรือโทเค็นที่อยู่ใกล้เคียงหรือโดยการประกาศล่วงหน้าของคำที่เป็นปัญหา) * ดังนั้นหากคุณต้องการใช้เป็นสตริงให้อ้างถึงและหากคุณต้องการใช้เป็นการเรียกใช้ฟังก์ชันให้ระบุไว้ล่วงหน้า หรือใช้วงเล็บ

Barewords เป็นอันตรายเนื่องจากพฤติกรรมที่คาดเดาไม่ได้นี้ use strict; (or use strict 'subs';)ทำให้สามารถคาดเดาได้เนื่องจากคำเปล่าที่อาจทำให้เกิดพฤติกรรมแปลก ๆ ในอนาคตจะทำให้โปรแกรมของคุณตายก่อนที่จะสร้างความหายนะ

มีสถานที่แห่งหนึ่งที่คุณสามารถใช้ barewords ได้แม้ว่าคุณจะเปิดการใช้งานแบบเข้มงวด: เมื่อคุณกำหนดแฮชคีย์

$hash{sample} = 6;   # Same as $hash{'sample'} = 6
%other_hash = ( pie => 'apple' );

Barewords ในแฮชคีย์ถูกตีความเป็นสตริงเสมอดังนั้นจึงไม่มีความคลุมเครือ

ใช้ 'refs' ที่เข้มงวด

สิ่งนี้จะสร้างข้อผิดพลาดขณะทำงานหากคุณใช้การอ้างอิงเชิงสัญลักษณ์ไม่ว่าจะโดยเจตนาหรืออย่างอื่น ค่าที่ไม่ได้มีการอ้างอิงที่ยากคือการได้รับการรักษาแล้วเป็นอ้างอิงสัญลักษณ์ นั่นคือการอ้างอิงถูกตีความเป็นสตริงที่แสดงชื่อของตัวแปรส่วนกลาง

use strict 'refs';

$ref = \$foo;       # Store "real" (hard) reference.
print $$ref;        # Dereferencing is ok.

$ref = "foo";       # Store name of global (package) variable.
print $$ref;        # WRONG, run-time error under strict refs.

ใช้คำเตือน

pragma ที่กำหนดขอบเขตคำศัพท์นี้ช่วยให้สามารถควบคุมคำเตือนในตัวของ Perl ได้อย่างยืดหยุ่นทั้งที่ปล่อยออกมาโดยคอมไพเลอร์และจากระบบรันไทม์

จากperldiag:

ดังนั้นข้อความเตือนส่วนใหญ่จากการจำแนกประเภทด้านล่างเช่น W, D & S สามารถควบคุมได้โดยใช้warningspragma

(W) คำเตือน (ทางเลือก)
(D) การเลิกใช้งาน (เปิดใช้งานโดยค่าเริ่มต้น)
(S) คำเตือนที่รุนแรง (เปิดใช้งานโดยค่าเริ่มต้น)

ฉันได้ระบุข้อความเตือนบางส่วนที่มักเกิดขึ้นด้านล่างตามการจำแนกประเภท สำหรับข้อมูลโดยละเอียดเกี่ยวกับพวกเขาและข้อความอื่น ๆ โปรดดูที่perldiag

(W) คำเตือน (ทางเลือก):

ไม่มีอาร์กิวเมนต์ใน% s ไม่มี
อาร์กิวเมนต์ถึง -% c
(คุณหมายถึง &% s แทนหรือไม่)
(คุณหมายถึง "local" แทน "ของเรา" หรือไม่)
(คุณหมายถึง $ หรือ @ แทน%?)
'% s 'ไม่ใช่รหัสอ้างอิง
length () ที่ใช้กับ% s
Misplaced _ in number

(D) การเลิกใช้งาน (เปิดใช้งานโดยค่าเริ่มต้น):

กำหนด (@array) เลิกใช้แล้ว
กำหนด (แฮช%) เลิกใช้แล้ว
เลิกใช้งานของฉัน () ในเงื่อนไขเท็จ
$ # ไม่ได้รับการสนับสนุนอีกต่อไป

(S) คำเตือนที่รุนแรง (เปิดใช้งานโดยค่าเริ่มต้น)

elseif ควรเป็น elsif
% s ที่พบในที่ที่คาดว่าจะมีตัวดำเนินการ
(ตัวดำเนินการหายไปก่อน% s?)
(ไม่มีเครื่องหมายอัฒภาคในบรรทัดก่อนหน้า?)
% s ไม่เคยแนะนำตัว
ดำเนินการหรืออัฒภาคที่ขาดหายไปก่อน% s
ปัญหาลำดับความสำคัญ: เปิด% s ควรเปิด (% s)
ต้นแบบไม่ตรงกัน:% s เทียบกับ% s
คำเตือน: การใช้ "% s" โดยไม่มีวงเล็บมีความคลุมเครือไม่
สามารถเปิด% s:% s


10

พร็อกมาสทั้งสองนี้สามารถระบุจุดบกพร่องในโค้ดของคุณโดยอัตโนมัติ

ฉันมักจะใช้สิ่งนี้ในรหัสของฉัน:

use strict;
use warnings FATAL => 'all';

FATALทำให้รหัสตายในคำเตือนเช่นเดียวกับที่strictทำ

สำหรับข้อมูลเพิ่มเติมโปรดดู: เข้มงวดยิ่งขึ้นด้วยคำเตือนการใช้งาน FATAL => 'all';

นอกจากนี้ ... ความเข้มงวดตาม Seuss


จริงๆแล้วคุณต้องหน่วงเวลาFATAL => "all"จนถึงรันไทม์โดยกำหนดให้$SIG{__WARN__} = sub { croak "fatalized warning @_" };หรือมิฉะนั้นคุณจะทำให้คอมไพเลอร์เสียหายโดยพยายามบอกคุณว่าต้องการอะไร
tchrist

6
@tchrist: สิ่งนี้ใช้ได้ผลกับฉันเสมอตามที่เป็นอยู่และเป็นเอกสาร หากคุณพบกรณีที่ไม่สามารถใช้งานได้ตามเอกสารโปรดแก้ไขเอกสารโดยใช้perlbug .
toolic

9

มีกระทู้ดีๆเกี่ยวกับคำถามนี้

เหตุผลพื้นฐานที่เห็นได้ชัดคือการเข้มงวดและคำเตือนช่วยให้คุณจับข้อผิดพลาดและช่วยแก้ไขข้อบกพร่องได้


3

ที่มา :: บล็อกต่าง

การใช้งานจะส่งออกฟังก์ชันและชื่อตัวแปรไปยังเนมสเปซหลักโดยเรียกใช้ฟังก์ชัน import () โมดูล

pragma เป็นโมดูลที่มีอิทธิพลต่อบางแง่มุมของเวลาในการคอมไพล์หรือพฤติกรรมเวลาทำงานของ perl.Pragmas ให้คำแนะนำแก่คอมไพเลอร์

ใช้คำเตือน - ข้อร้องเรียน perl เกี่ยวกับตัวแปรที่ใช้เพียงครั้งเดียวการแปลงสตริงเป็นตัวเลขที่ไม่เหมาะสมการพยายามเขียนไปยังไฟล์ที่ไม่ได้เปิดมันเกิดขึ้นในเวลาคอมไพล์ใช้เพื่อควบคุมคำเตือน

ใช้เข้มงวด - ประกาศขอบเขตตัวแปร ใช้เพื่อกำหนดระเบียบวินัยบางอย่างในสคริปต์หากใช้ barewords ในโค้ดจะมีการตีความตัวแปรทั้งหมดควรกำหนดขอบเขตเช่น my, our หรือ local


1

คำสั่ง "ใช้อย่างเข้มงวด" จะบอกให้ Perl ทำการตรวจสอบเพิ่มเติมในระหว่างการรวบรวมโค้ดของคุณ การใช้คำสั่งนี้จะช่วยให้คุณประหยัดเวลาในการดีบักรหัส Perl ของคุณเนื่องจากพบข้อบกพร่องในการเข้ารหัสทั่วไปที่คุณอาจมองข้ามไป


0

เข้มงวดและคำเตือนตรวจสอบให้แน่ใจว่าตัวแปรของคุณไม่ใช่ทั่วโลก

เป็นเรื่องที่ดีกว่ามากที่จะมีตัวแปรเฉพาะสำหรับแต่ละวิธีแทนที่จะต้องติดตามชื่อตัวแปรแต่ละตัว

$ _ หรือไม่มีตัวแปรสำหรับฟังก์ชันบางอย่างอาจมีประโยชน์ในการเขียนโค้ดที่กะทัดรัดมากขึ้นได้เร็วขึ้น

อย่างไรก็ตามหากคุณไม่ใช้คำเตือนและคำเตือนที่เข้มงวด $ _ จะกลายเป็นสากล!


0
use strict;
use warnings;

เข้มงวดและคำเตือนเป็นโหมดสำหรับโปรแกรม perl ช่วยให้ผู้ใช้ป้อนรหัสได้อย่างเสรีมากขึ้นและยิ่งไปกว่านั้นรหัส perl นั้นจะดูเป็นทางการและมาตรฐานการเข้ารหัสจะมีผลบังคับใช้

คำเตือนมีความหมายเหมือนกัน-wในบรรทัด perl shebang ดังนั้นจะให้คำเตือนที่สร้างโดยโปรแกรม perl ซึ่งจะแสดงในเทอร์มินัล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.