1

私は次のサブを宣言しました(実際には、値はデータベースから取得されるため、単純化しました):

sub get_date {
 my ($ref_last)=@_;
 $$ref_last->{duration}='24,0,4';
 ($$ref_last->{duration}->{d},
  $$ref_last->{duration}->{h},
  $$ref_last->{duration}->{m})
   = split(/\,/, $$ref_last->{duration});
}

このサブは、次のように、スクリプトのメイン部分から呼び出されます。

my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

strictを使用するまでは、すべてが正常で、魅力のように機能します。

use strict;
my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

この場合、perlは「文字列(「24,0,4」)をハッシュ参照として使用できませんが、「厳密な参照」は使用中です」と表示します

すでに試しref($ref_last)ましたrefが、読み取り専用の関数です。

何か提案、なぜこれが起こるのか-そしておそらくより良い解決策?

これが完全な(非)動作スクリプトです:

#!/usr/bin/perl -w
use strict;
my $hashy;
get_date(\$hashy);
print $hashy->{duration}->{d};

sub get_date {
        my ($ref_last)=@_;
        $$ref_last->{duration}='24,0,4';
        ($$ref_last->{duration}->{d},
         $$ref_last->{duration}->{h},
         $$ref_last->{duration}->{m})
                = split(/\,/, $$ref_last->{duration});
}
4

3 に答える 3

2

コメントに基づいて、既存のハッシュ値の形式を(« 24,0,4»から« { d=>24, h=>0, m=>4 }»に)変更しようとしています。これが私がそれをする方法です。

sub split_duration {  # Changes in-place.
    my ($duration) = @_;
    my %split;
    @split{qw( d h m )} = split(/,/, $duration);
    $_[0] = \%split;
}

my $row = $sth->fetchrow_hashref();
split_duration( $row->{duration} );

また

sub split_duration {
    my ($duration) = @_;
    my %split;
    @split{qw( d h m )} = split(/,/, $duration);
    return \%split;
}

my $row = $sth->fetchrow_hashref();
$row->{duration} = split_duration( $row->{duration} );

以下の問題と初期解決策の説明。


厳密に指定しない24,0,4と、ハッシュ参照として扱われました。これは、Perlが$24,0,4!!!という名前の変数を作成していたことを意味します。それは悪いことです、それがそれをuse strict 'refs';防ぐ理由です。

$$ref_last->{duration}根本的な問題は、2つの値を文字列に割り当てようとすることです。

'24,0,4'

とハッシュへの参照

 { d => 24, h => 0, m => 4 }

両方を保持することはできません。データを再配置する必要があります。

分割した後は実際には使用しないと思わ24,0,4れるので、次のようにコードを修正できます。

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}

必要24,0,4に応じて、再構築できます。または、d、h、mとともに合計期間を保存することもできます。

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    $$ref_last->{duration}{full} = $duration;
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}

または、上位ハッシュの別の要素で。

sub get_date {
    my ($ref_last)=@_;
    my $duration = '24,0,4';
    $$ref_last->{full_duration} = $duration;
    @{ $$ref_last->{duration} }{qw( d h m )} =
        split(/,/, $duration);
}
于 2012-05-23T18:40:18.943 に答える
2

内部get_dateでは、文字列をに割り当てますが$ref_last->{duration}、hashrefのようにそれにアクセスしようとします。また、ハッシュから抽出された個々の値を逆参照しようとする余分なドル記号もあります。

私はそれを次のように書きます

sub get_date {
  my($ref_last) = @_;
  my $duration = '24,0,4';
  @{ $ref_last->{duration} }{qw/ d h m /} = split /\,/, $duration;
}

最後の行は、単一のリスト割り当てで、、、およびキーに値を割り当てることができるハッシュスライスです。dhm

発信者のコンテキストでは、足場を少し設定する必要があります。

my $hashy = {};
get_date($hashy);

$hashy新しい空のhashrefを含むように初期化せずに、get_dateすべての割り当てを実行してから、新しく構築された建物を破棄します。これは、からパラメータをコピーするときに@_、値渡しのセマンティクスを使用しているためです。

Perlは参照渡しにも対応します。Perlには、言語がオンデマンドで必要な足場を構築する自動生存と呼ばれる機能があります。そのスタイルを使用するには、次のように記述します

my $hashy;
get_date($hashy);

sub get_date {
  my($ref_last) = @_;
  my $duration = '24,0,4';
  @{ $_[0]->{duration} }{qw/ d h m /} = split(/\,/, $duration);
}

$_[0]を使用して最初のパラメータに直接アクセスすることに注意してください。この場合は、のエイリアスです。$hashyつまり、直接get_date変更$hashyします。

いずれにせよ、コンテンツを次のように印刷するとします

print "[", join("][" => %{ $hashy->{duration} }), "]\n";

この場合、出力は次の順列になります。

[h] [0] [m] [4] [d] [24]

Perlを使用して複雑なデータ構造を構築することは難しくありませんが、ルールを学ぶ必要があります。

于 2012-05-23T18:56:58.237 に答える
0

これは、ハッシュ参照の構文がおかしいために発生します。

#!/usr/bin/perl -w
use strict;

my $hashref = {};
get_date($hashref);

print $hashref->{duration}->{d};

sub get_date {
    my ($ref_last) = @_;
    $tmp = '24,0,4';

    ($ref_last->{duration}->{d},
     $ref_last->{duration}->{h},
     $ref_last->{duration}->{m})
            = split(/,/, $tmp);
}

サブルーチンでは、を使用$ref_last->{duration}せずに、を使用します$$

于 2012-05-23T18:17:30.947 に答える