2011-01-24 18 views
1

我在它與下面的語句的文件:Perl:do和eval會導致不同的答案?

{ 
     %{do '/tmp/personcontact.pl'}, 
     %{do '/tmp/address.pl'} 
    } 

現在,臨時文件如下: Personcontact.pl:

  { 
     'firstname' => { 
      '__type' => 'String' 
      }, 
     'lastname' => { 
      '__type' => 'String' 
      } 
    } 

Address.pl:

 { 
     'address' => { 
      'street' => { 
       '__type' => 'String' 
       }, 
      'unit' => { 
       '__type' => 'String', 
      }, 
      'suburb' => { 
       '__type' => 'String' 
      }, 
      '__type' => 'HASH' 
     } 
    } 

現在,當我這樣做:

open(SCHEMAFILE, "<", $schema) or return undef; 
my $schemafile;  
while(my $line = <SCHEMAFILE>) { $schemafile .= $line;} 
my $tempref = eval $schemafile; 
print Dumper $tempref; 

結果是$VAR1 = '1/8'

當我做:

print Dumper do "/tmp/schemawithinschema.pl"; 

結果是

    $VAR1 = 'firstname'; 
     $VAR2 = { 
      '__type' => 'String' 
      }; 
     $VAR3 = 'address'; 
     $VAR4 = { 
      'suburb' => { 
        '__type' => 'String' 
       }, 
      'unit' => { 
       '__type' => 'String' 
       }, 
      'street' => { 
        '__type' => 'String' 
       }, 
      '__type' => 'ARRAY' 
      }; 
     $VAR5 = 'lastname'; 
     $VAR6 = { 
      '__type' => 'String' 
      }; 

有什麼不對嗎?謝謝!

+9

Hooooooooly牛。手動迭代(全局!)文件句柄SCHEMAFILE然後對其進行評估的部分是我上次告訴你的那個部分,這正是「做」的工作。你也是......只是......是的。 ** cry **把這些數據放入一個JSON或YAML文件中,相比之下,它的維護要容易900倍。 – 2011-01-24 08:23:38

+0

同意。只有基於可存儲的配置在維護方面更糟糕。 (我甚至寫了一個腳本,做了一個Storable-> Dumper-> vim-> Dumper-> Storable轉換。) – Dallaylaen 2011-01-24 08:34:02

回答

9

好了,保持這個距離永遠延續,這是給你一個基於模塊的解決方案:

Foo.pm:

package Foo; 

use strict; 
use warnings; 

BEGIN { 
    require Exporter; 
    our @ISA = qw(Exporter); 
    our @EXPORT_OK = qw(get_person get_address get_all); 
    our $VERSION = '0.01'; 
} 

my %person = (
    firstname => { 
     __type => 'String', 
    }, 
    lastname => { 
     __type => 'String', 
    }, 
); 

my %address = (
    address => { 
     street => { 
      __type => 'String', 
     }, 
     unit => { 
      __type => 'String', 
     }, 
     suburb => { 
      __type => 'String', 
     }, 
     __type => 'HASH', 
    }, 
); 

sub get_person 
{ 
    return \%person; 
} 

sub get_address 
{ 
    return \%address; 
} 

sub get_all 
{ 
    return({ %person, %address }); 
} 

1; 

__END__ 

bar.pl:

#!/usr/bin/perl 

use Data::Dumper; 
use strict; 
use warnings; 
use lib '.'; 
use Foo qw(get_person get_address get_all); 

my $junk = get_all(); 

print Dumper $junk; 

真的是,爲了您的維護程序員(通常在6個月以內),請使用JSONYAML(或f aster YAML::XS),因此數據可以作爲簡單的文本文件來維護,而不是一系列嵌套的數據僞裝成代碼引用。

引述Perl Best Practices(不知道這是否是達米安原本):

始終代碼,如果誰最終維護你代碼的傢伙將是一個暴力變態誰知道你住在哪裏。


EDIT:爲了完整起見,在這裏是使用YAML等效溶液(來自CPAN):

data.yml:

--- 
firstname: 
    __type: String 
lastname: 
    __type: String 
address: 
    __type: HASH 
    street: 
    __type: String 
    suburb: 
    __type: String 
    unit: 
    __type: String 

baz.pl:

#!/usr/bin/perl 

use YAML qw(Load Dump LoadFile DumpFile); 
use Data::Dumper; 
use strict; 
use warnings; 

my $data = LoadFile('data.yml'); 
print Dumper $data; 
4

One p ointer。 '1/8'是你在標量上下文中評估一個散列時得到的結果。 8是分配給散列的桶的數量,1是正在使用的桶的數量。

這通常是無用的,除了作爲一個標誌,你做錯了什麼。

5

雖然問題的目的讓我哭,但兩個代碼片段之間的區別與doeval無關,並且與上下文有關。由於這是一個合法的Perl主題,我將簡要回答它。

my $tempref = eval $schemafile; 

,所述eval發生在標量上下文(由分配強加$tempref)。但是,$schemafile包含由散列引用取消引用運算符%{}創建的散列。當該散列評估爲標量時,它產生一個散列的正常行爲1/8

print Dumper do "/tmp/schemawithinschema.pl"; 

,該do發生在由Dumper調用(這又是在print列表上下文中)所規定的列表環境。 do創建了與eval相同的散列,但現在它正在列表上下文中進行評估,實際上是作爲Dumper的參數列表。頂級哈希變成了一個Label => HashRef對列表,但這不足以阻止Dumper能夠向您顯示看起來很像您嘗試創建的哈希的東西。

爲了將來的參考,當在兩種情況下試圖找出一個奇怪的行爲差異來呈現完全相同的調用時,它是有幫助的。兩個測試用例之間的變量越多,你越不關心的事情越多,就會引起關注並使你感到困惑。

所有這一切都說,真正的答案是「這裏有什麼問題?」仍然「試圖做到這一點」。