كيف يمكنني الوصول إلى ثابت في بيرل الذي يوجد اسمه في متغير؟

StackOverflow https://stackoverflow.com/questions/2187682

  •  25-09-2019
  •  | 
  •  

سؤال

لدي مجموعة من الثوابت المعلنة في بيرل:

   use constant C1 => 111;
   use constant C2 => 222;
   ..
   use constant C9 => 999;
   my $which_constant = "C2";

كيف أقوم ببناء تعبير بيرل والذي يعتمد على $which_constant, ، يستمد قيمة الثابت المسمى مع قيمة هذا المتغير - على سبيل المثال "222".

يرجى ملاحظة أنه لا يمكنني تغيير أي من الشروط المذكورة أعلاه - فهي تبسيط لسيناريو حقيقي: لدي وحدة نمطية (التي ليس لدي أي سيطرة عليها) يتم استيراد هذه الثوابت منها. يتم توفير اسم أحد الثوابت من قبل المستخدم من سطر الأوامر. أحتاج إلى الوصول إلى قيمة الثوابت المناسبة.

لقد ضربت رأسي على الحائط (معظمها حول جميع أنواع بنيات الكرة الأرضية الغريبة) ولكن لا شيء منهم يعمل.

ملاحظة إذا كان الحل يصل إلى الثوابت داخل الوحدة الأصلية - قل My::Constants::C2 (دون الحاجة إلى استيرادها) ، حتى أفضل ، ولكن ليس ضروريًا - يمكنني استيراد الثوابت الصحيحة إليها main:: باستخدام بسهولة My::Constants->import($which_constant). ونعم ، لتتصدر ذلك ، لا يتم تصدير ثوابت TE افتراضيًا وبالتالي تحتاج إلى استدعاء الاستيراد الصريح ().

بعض الأشياء التي جربتها:

  • main::$which_constant - خطأ في بناء الجملة

  • main::${which_constant} - خطأ في بناء الجملة

  • ${*$which_constant} - إرجاع القيمة الفارغة

  • *$which_constant - إرجاع "*Main :: C2"

  • ${*${*which_constant}} - فارغة

هل كانت مفيدة؟

المحلول

الثوابت المحددة من قبل constant.pm هي مجرد روتين فرعي. يمكنك استخدام بناء جملة Method Invocation إذا كان لديك اسم الثابت في السلسلة:

#!/usr/bin/perl -l

use strict; use warnings;
use constant C1 => 111;
use constant C2 => 222;

print __PACKAGE__->$_ for qw( C1 C2 );
# or print main->$_ for qw( C1 C2 );

وبهذه الطريقة ، إذا حاولت استخدام ثابت لم يتم تعريفه ، فستحصل على خطأ.

نصائح أخرى

Perl "الثوابت" هي في الواقع برامج فرعية تُرجع قيمة ثابتة. المترجم بيرل قادر على استبداله بالقيمة المناسبة في وقت الترجمة. ومع ذلك ، نظرًا لأنك تريد الحصول على القيمة بناءً على بحث اسم وقت التشغيل ، يجب عليك القيام بذلك:

&{$which_constant}();

(وبالطبع تحتاج no strict 'refs' مكان ما.)

اقتراح سنان لاستخدام دلالات استدعاء الطريقة للالتفاف strict 'refs' الحدود هي أنظف وأسهل حل القراءة.

كان قلقي الوحيد بشأن هذا هو أن عقوبة السرعة لاستخدام هذا النهج قد تكون مشكلة. لقد سمعنا جميعًا عن عقوبات أداء الطريقة وفوائد السرعة للوظائف القابلة للتطبيق.

لذلك قررت تشغيل معيار (الكود والنتائج التالية).

تُظهر النتائج أن الثوابت العادية المقلقة تعمل حوالي ضعف أسرع ما يتصل به الأسلوب باسم روتين فرعي حرفي ، وما يقرب من ثلاث مرات بالسرعة التي تتصل بها الطريقة بأسماء روتين فرعي متغير. أبطأ النهج هو deref القياسي والاستدعاء no strict "refs";.

ولكن ، حتى أبطأ النهج هو سريع للغاية في أكثر من 1.4 مليون مرة في الثانية على نظامي.

هذه المعايير طمس تحفظتي حول استخدام نهج استدعاء الطريقة لحل هذه المشكلة.

use strict;
use warnings;

use Benchmark qw(cmpthese);

my $class = 'MyConstant';
my $name  = 'VALUE';
my $full_name = $class.'::'.$name;


cmpthese( 10_000_000, {
    'Normal'      => \&normal_constant,
    'Deref'       => \&direct_deref,
    'Deref_Amp'   => \&direct_deref_with_amp,
    'Lit_P_Lit_N' => \&method_lit_pkg_lit_name,
    'Lit_P_Var_N' => \&method_lit_pkg_var_name,
    'Var_P_Lit_N' => \&method_var_pkg_lit_name,
    'Var_P_Var_N' => \&method_var_pkg_var_name,
});

sub method_lit_pkg_lit_name {
    return 7 + MyConstant->VALUE;
}

sub method_lit_pkg_var_name {
    return 7 + MyConstant->$name;
}

sub method_var_pkg_lit_name {
    return 7 + $class->VALUE;
}

sub method_var_pkg_var_name {
    return 7 + $class->$name;
}

sub direct_deref {
    no strict 'refs';
    return 7 + $full_name->();
}

sub direct_deref_with_amp {
    no strict 'refs';
    return 7 + &$full_name;
}

sub normal_constant {
    return 7 + MyConstant::VALUE();
}

BEGIN {
    package MyConstant;

    use constant VALUE => 32;
}

والنتائج:

                 Rate Deref_Amp Deref Var_P_Var_N Lit_P_Var_N Lit_P_Lit_N Var_P_Lit_N Normal
Deref_Amp   1431639/s        --   -0%         -9%        -10%        -29%        -35%   -67%
Deref       1438435/s        0%    --         -9%        -10%        -28%        -35%   -67%
Var_P_Var_N 1572574/s       10%    9%          --         -1%        -22%        -29%   -64%
Lit_P_Var_N 1592103/s       11%   11%          1%          --        -21%        -28%   -63%
Lit_P_Lit_N 2006421/s       40%   39%         28%         26%          --         -9%   -54%
Var_P_Lit_N 2214349/s       55%   54%         41%         39%         10%          --   -49%
Normal      4353505/s      204%  203%        177%        173%        117%         97%     --

النتائج التي تم إنشاؤها باستخدام ActivePerl 826 على Windows XP ، YMMV.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top