2010-10-12 34 views
16

Khi đánh giá một biểu thức trong ngữ cảnh vô hướng (boolean), Perl sử dụng giá trị rõ ràng 1 như là kết quả nếu biểu thức đánh giá đúng và chuỗi trống nếu biểu thức đánh giá sai. Tôi tò mò tại sao Perl sử dụng chuỗi rỗng để biểu diễn giá trị sai boolean chứ không phải 0 có vẻ trực quan hơn.Tại sao Perl sử dụng chuỗi rỗng để biểu thị giá trị sai boolean?

Lưu ý rằng tôi không quan tâm đến Perl xử lý chuỗi rỗng làm sai trong ngữ cảnh vô hướng (boolean).

EDIT

Làm thế nào sử dụng chuỗi đó là sự thật ("false" ví dụ) như là một chuỗi đại diện của các giá trị sai sẽ thay đổi ý nghĩa của mã hiện tại? Chúng ta có thể nói rằng mã thay đổi ngữ nghĩa sau khi một thay đổi như vậy là ít mạnh mẽ/chính xác hơn nó có thể có được? Tôi đoán bối cảnh chuỗi là phổ biến trong Perl rằng tùy chọn duy nhất dẫn đến ngữ nghĩa lành mạnh là nếu giá trị boolean giữ giá trị của nó sau khi vấp tròn đến và đi từ một chuỗi ...

+0

Bản sao có thể có của [Tại sao! 1 cho tôi không có gì trong Perl?] (Http://stackoverflow.com/questions/1134962/why-does-1-give-me-nothing-in-perl) – Thilo

Trả lời

30

Các toán tử logic khác nhau không trả về một chuỗi rỗng, chúng trả về một giá trị sai hoặc đúng trong cả ba loại vô hướng đơn giản. Nó chỉ có vẻ như nó trả về một chuỗi rỗng vì print buộc một bối cảnh chuỗi trên đối số của nó:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Devel::Peek; 

my $t = 5 > 4; 
my $f = 5 < 4; 

Dump $t; 
Dump $f; 

Output:

SV = PVNV(0x100802c20) at 0x100827348 
    REFCNT = 1 
    FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK) 
    IV = 1 
    NV = 1 
    PV = 0x100201e60 "1"\0 
    CUR = 1 
    LEN = 16 
SV = PVNV(0x100802c40) at 0x100827360 
    REFCNT = 1 
    FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK) 
    IV = 0 
    NV = 0 
    PV = 0x100208ca0 ""\0 
    CUR = 0 
    LEN = 16 

Đối với những người không quen thuộc với Perl 5 internals, một PVNV là một vô hướng cấu trúc chứa tất cả ba loại vô hướng đơn giản (số nguyên IV, phao chính xác kép NV và chuỗi PV). Các cờ IOK, NOKPOK có nghĩa là tất cả các giá trị số nguyên, đôi và chuỗi đều được đồng bộ hóa (đối với một số định nghĩa đồng bộ) để bất kỳ một trong số chúng có thể được sử dụng (tức là không cần chuyển đổi nếu bạn sử dụng nó dưới dạng số nguyên, gấp đôi hoặc chuỗi).

Tôi giả định chuỗi rỗng đã được chọn cho chuỗi sai vì nó nhỏ hơn và phù hợp hơn với ý tưởng về chuỗi sai hơn "0". Bỏ qua tuyên bố của tôi về nó nhỏ hơn, cả hai """1" có cùng kích thước: mười sáu ký tự. Nó nói như vậy ngay trong bãi chứa. Perl 5 bổ sung thêm không gian cho các chuỗi để cho phép chúng phát triển nhanh chóng.

Ồ, và tôi ghét bạn. Trong nghiên cứu này tôi đã tìm thấy rằng tôi đã nói dối trong perlopquick và bây giờ sẽ phải tìm một cách để sửa chữa nó. Nếu chỉ có bạn giống như tất cả những con cừu khác và chỉ chấp nhận sự kỳ lạ bề ngoài của Perl 5 là sự thật, tôi sẽ có ít việc phải làm hơn.

Câu trả lời cho các câu hỏi trong phần EDIT:

Làm thế nào sẽ sử dụng chuỗi đó là sự thật ("false" chẳng hạn) như một chuỗi đại diện của các giá trị sai thay đổi ý nghĩa của mã hiện tại?

duy nhất điều đặc biệt về khoảng PL_sv_yes và PL_sv_no (các giá trị giáo luật true và false trả về bởi toán tử so sánh) được rằng họ được chỉ đọc và được tạo ra bởi perl không phải là chương trình đang chạy. Nếu bạn thay đổi chúng, nó không thay đổi kiểm tra sự thật, vì vậy một PL_sv_no được đặt là "false" sẽ được coi là đúng. Bạn thậm chí có thể làm điều này cho mình (mã này ngừng hoạt động tại một số điểm giữa Perl 5.18 và sự Perl mới nhất) sử dụng các tính năng không có giấy tờ của perl:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Scalar::Util qw/dualvar/; 

BEGIN { 
     # use the undocumented SvREADONLY function from Internals to 
     # modify a reference to PL_sv_no's readonly flag 
     # note the use of & to make the compiler not use SvREADONLY's 
     # prototype, yet another reason prototypes are bad and shouldn't 
     # be used 
     &Internals::SvREADONLY(\!!0, 0); 

     # set PL_sv_no to a dualvar containing 0 and "false" 
     ${\!!0} = dualvar 0, "false"; 
} 

if (5 < 4) { 
     print "oops\n"; 
} 

đầu ra

opps 

Điều này là do ngoại hình thử nghiệm truthiness tại chuỗi đầu tiên.

Chúng ta có thể nói rằng mã thay đổi ngữ nghĩa sau khi thay đổi như vậy ít mạnh mẽ/chính xác hơn so với nó có thể là?

Nó sẽ bị hỏng thẳng. Ngay cả khi bạn giới hạn bản thân để đặt nó thành một int 0 hoặc một chuỗi "0" (cả hai đều sai), nó sẽ phá vỡ một số mã hợp lệ.

Tôi đoán chuỗi bối cảnh rất phổ biến trong Perl rằng lựa chọn duy nhất dẫn đến ngữ nghĩa lành mạnh là nếu giá trị boolean duy trì giá trị của nó sau khi vòng vấp ngã đến và đi từ một chuỗi ...

Yes.

+9

Tôi ghét/yêu cả hai bạn - câu hỏi này đã khiến tôi gửi một mẩu tin đến p5p ngay bây giờ: những sai lầm ám chỉ đến 'PL_sv_no' (vô hướng" vô hướng trong câu hỏi) là 'PL_sv_false'. :) – hobbs

+2

@Piotr Dobrogost Xem những gì bạn đã làm! Xem những gì đến từ việc đặt câu hỏi? Bạn đang làm mọi thứ trong Perl 5 tốt hơn! Làm thế nào bạn có thể sống với chính mình? –

+0

Cảm ơn, áp dụng, hobbs. :-) – rafl

2

It's not just"" that's false in Perl. Đối với lý do tại sao ... đó là vì Perl là tuyệt vời hoặc khủng khiếp - tùy thuộc vào sở thích cá nhân của bạn :)

+1

Perl là ngôn ngữ duy nhất có thể đọc được trước và sau khi mã hóa RSA. – TBH

+2

@TBH Không, APL là. Perl có thể đọc được nhiều hơn ở dạng không được mã hóa. –

+2

@Chas - Tôi nghĩ bạn muốn nói "ở dạng mã hóa". – DVK

2

Cả số 0 và chuỗi rỗng cuối cùng được đánh giá là sai trong Perl. Tôi nghĩ đây là vấn đề thiết kế ngôn ngữ. Khi viết mã của riêng bạn, tất nhiên bạn có thể giả định bất kỳ quy ước mã hóa sai nào.

Để biết thêm chi tiết, hãy xem "How do I use boolean variables in Perl?".

5

Bạn có thể quá tải stringification true, false và undef, như this:

&Internals::SvREADONLY(\ !!1, 0); # make !!1 writable 
${ \ !!1 } = 'true';     # change the string value of true 
&Internals::SvREADONLY(\ !!1, 1); # make !!1 readonly again 
print 42 == (6*7);     # prints 'true' 

&Internals::SvREADONLY(\ !!0, 0); # make !!0 writable 
${ \ !!0 } = 'false';     # change the string value of false 
&Internals::SvREADONLY(\ !!0, 1); # make !!0 readonly again 
print 42 == (6*6);     # prints 'false' 
+0

Tùy chỉnh rất đẹp. Tôi không biết Perl cho phép một thứ như thế. –

+3

Rất sai. +1. – rafl

+0

Gói 'Nội bộ 'và các chức năng hoặc các biến trong đó không dành cho tiêu dùng công cộng (do đó tên). Thay đổi toàn cầu giá trị của các giá trị đúng và sai được trả về bởi các toán tử là vô tình trong cực đoan. Phá vỡ nguyên mẫu của 'SvREADONLY' chỉ đóng băng trên bánh. Điều đó nói, tiện lợi. –

1

Dưới đây là làm thế nào tôi có xung quanh các vấn đề:

my $res = ($a eq $b) *1; 

Các *1 chuyển đổi boolean do ($a eq $b) thành một vô hướng.

Các vấn đề liên quan