ทำไมผู้ใช้บางคนพูดชื่อคลาสใน Perl?


12

มองไปที่Type::Tinyฉันเห็นว่าชื่อชั้นในการโทรไปยังType::Tiny->newอ้างถึงในเอกสารอย่างเป็นทางการ

my $NUM = "Type::Tiny"->new(
   name       => "Number",
   constraint => sub { looks_like_number($_) },
   message    => sub { "$_ ain't a number" },
);

ทำไมนี้ สไตล์นี้เป็นเพียง? มีผลการปฏิบัติงานสำหรับการฝึกฝนนี้ไหม?

คำตอบ:


7

ยกตัวอย่างง่ายๆ

package Foo { sub new { die 7  } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();

ในตัวอย่างข้างต้นคงFooมีมติให้ "บาร์" ดังนั้นเพื่อให้สายนี้ไม่ได้"Bar"->new "Foo"->newคุณจะหยุดรูทีนย่อยจากการแก้ไขได้อย่างไร? คุณสามารถพูดได้

"Foo"->new();

สำหรับนัยเกี่ยวกับประสิทธิภาพการทำงานสิ่งต่าง ๆ ไม่ได้แย่ลงไปกว่าการใช้สายอักขระแทนที่จะเป็นคำสั่ง ฉันยืนยันว่า optree ที่สร้างโดยO=Deparseเหมือนกัน ตามกฎทั่วไปดูเหมือนว่าจะเป็นการดีกว่าถ้าคุณอ้างความถูกต้องของ Classname

สิ่งนี้ถูกกล่าวถึงในการเขียนโปรแกรม Perl, (น่าเศร้าในบริบทของการเรียกใช้เมธอดทางอ้อม )

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

use ElvenRing;
require ElvenRing;

การประกาศอย่างใดอย่างหนึ่งเหล่านี้ทำให้มั่นใจได้ว่า Perl รู้ว่าElvenRingเป็นชื่อโมดูลซึ่งบังคับให้ชื่อใด ๆ ที่ไม่เหมือนnewก่อนที่ชื่อคลาสElvenRingที่จะตีความว่าเป็นวิธีการโทรแม้ว่าคุณจะเกิดขึ้นได้ประกาศnewsubroutine ของคุณเองในแพคเกจปัจจุบัน

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

TLDR; มันอาจจะเป็นความคิดที่ดีที่จะอ้างชื่อคลาสของคุณถ้าคุณรู้ว่าพวกเขาและคุณให้คุณค่าความถูกต้องมากกว่าความยุ่งเหยิง

บันทึก Side: อีกทางเลือกหนึ่งให้คุณสามารถหยุดความละเอียดของ bareword ให้ฟังก์ชั่นด้วยการติดตราไปยังจุดสิ้นสุดของมันตัวอย่างเช่นในข้างต้น::Foo::->new


ขอบคุณGinnz ที่ reddit สำหรับการชี้ให้ฉันและToby Inkster สำหรับความคิดเห็น (แม้ว่ามันจะไม่สมเหตุสมผลสำหรับฉันในการอ่านครั้งแรก)


2
หรือFoo::->newอย่างที่ฉันเรียนรู้จาก ikegami
ม็อบ

@mob ใช่แล้วหนังสือ Perl ระบุด้วยเหมือนกัน (ชัดเจน) ไม่แน่ใจว่าฉันควรใส่มันไว้ที่นั่นหรือไม่? ฮ่า ๆ.
Evan Carroll

@mob ฉันได้เพิ่มสิ่งนั้นด้วยเป็นเชิงอรรถ แม้ว่าฉันไม่แน่ใจว่าฉันชอบมัน
Evan Carroll

1
Foo::มีข้อได้เปรียบที่จะเตือนถ้าFooไม่ใช่แพ็คเกจที่มีอยู่
ikegami

1
ลอง :: Tiny เป็นตัวอย่างที่ดีกว่า Foo ในรหัสของคุณโดยใช้Foo->คุณสามารถคาดหวังว่าจะไม่มีรูทีนย่อยดังกล่าวในแพ็คเกจของคุณ แต่ถ้าคุณใช้ Try :: Tiny และ cpan / โมดูลอื่น ๆ ที่มาจากภายนอกอื่น ๆ อีกมากมายใครจะบอกว่าหนึ่งในนั้นกำลังใช้ Try package และถ้าเป็นเช่นนั้นถ้ามี Tiny ย่อยอยู่ในนั้น?
ysth

0

การอ้างชื่อคลาสอย่างชัดเจนแทนที่จะใช้ bareword (ซึ่งถือว่าเป็นสตริง) เป็นหนึ่งในสามวิธีในการหลีกเลี่ยงความคลุมเครือทางไวยากรณ์ อัญเชิญวิธีการเรียนส่วนหนึ่งของเอกสาร perlobjอธิบาย

เนื่องจาก Perl อนุญาตให้คุณใช้ barewords สำหรับชื่อแพ็กเกจและชื่อรูทีนย่อยบางครั้งก็ตีความความหมายของ bareword อย่างไม่ถูกต้อง ตัวอย่างเช่นการสร้างClass->new()สามารถตีความได้ว่าเป็นอย่างใดอย่างหนึ่ง'Class'->new()หรือClass()->new(). ในภาษาอังกฤษการตีความที่สองอ่านว่า "เรียกรูทีนย่อยชื่อClass()แล้วเรียกnew()ว่าเป็นวิธีการเกี่ยวกับค่าตอบแทนของClass()." หากมีการย่อยชื่อClass()ใน namespace ปัจจุบัน Perl มักจะตีความClass->new()เป็นทางเลือกที่สอง: การเรียกร้องให้ บนวัตถุที่ส่งกลับโดยการเรียกไปยังnew()Class()

ดูกรณีแปลก ๆ นี้พร้อมตัวอย่างด้านล่าง

#! /usr/bin/env perl

use strict;
use warnings;

sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }

sub Type::Tiny::new { print "Type::Tiny::new\n" }

sub Bogus::new { print "Bogus::new\n" }

my $class = "Type::Tiny";

Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;

เอาท์พุทมันคือ

เป็นการหลอกลวง
ปลอม :: ใหม่
ประเภท :: จิ๋ว :: ใหม่
ประเภท :: จิ๋ว :: ใหม่
ประเภท :: จิ๋ว :: ใหม่

ส่วนที่เหลือของส่วนเอกสารดังกล่าวแสดงวิธีการป้องกันพฤติกรรมที่น่าแปลกใจหรือข้อผิดพลาดโดยไม่ตั้งใจ

คุณสามารถบังคับให้ Perl ใช้การตีความแรก ( เช่นการเรียกเมธอดบนคลาสที่มีชื่อ"Class") ได้สองวิธี ก่อนอื่นคุณสามารถต่อท้าย::ชื่อคลาสได้:

Class::->new()

Perl จะตีความสิ่งนี้เป็นการเรียกเมธอดเสมอ

หรือคุณสามารถอ้างอิงชื่อคลาสได้:

'Class'->new()

แน่นอนถ้าชื่อคลาสอยู่ในสเกลาร์ Perl จะทำสิ่งที่ถูกต้องเช่นกัน:

my $class = 'Class';
$class->new();

นำไปใช้กับคำถามของคุณการโทรทั้งหมดด้านล่างนี้เทียบเท่ากัน

Type::Tiny::->new(  );

"Type::Tiny"->new(  );

my $class = "Type::Tiny";
$class->new(  );

การผนวก::ไปยังจุดสิ้นสุดมีประโยชน์ในการสร้างคำเตือนที่มีประโยชน์ สมมติว่าคุณพิมพ์โดยไม่ตั้งใจ

Type::Tinny::->new;

ที่ผลิต

Bareword "Type :: Tinny ::" หมายถึงแพ็คเกจที่ไม่มีอยู่ที่. / ลองบรรทัดที่ 15
ไม่สามารถหาวิธีวัตถุ "ใหม่" ผ่านแพคเกจ "ประเภท :: Tinny" (บางทีคุณลืมโหลด "Type :: Tinny"?) ที่. / ลองบรรทัดที่ 15
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.