سؤال

ولدي وظيفة التي تأخذ متغير ومجموعة النقابي، ولكن أنا لا يمكن أن يبدو للحصول عليها لتمرير الصحيح. أعتقد أن هذا له علاقة مع الإعلانات وظيفة، ولكن أنا لا يمكن معرفة كيفية عملها في بيرل. هناك إشارة جيدة لهذا وكيف يمكنني تحقيق ما أحتاج؟

وأود أن أضيف أنه يحتاج لتمريرها حسب المرجع.

sub PrintAA
{
    my $test = shift;
    my %aa   = shift;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
        $aa{$_} = $aa{$_} . "+";
    }
}
هل كانت مفيدة؟

المحلول

وتمرير الإشارة بدلا من البعثرة نفسها. كما هو الحال في

PrintAA("abc", \%fooHash);

sub PrintAA
{
  my $test = shift;
  my $aaRef = shift;

  print $test, "\n";
  foreach (keys %{$aaRef})
  {
    print $_, " : ", $aaRef->{$_}, "\n";
  }
}

وانظر perlfaq7 أيضا: <لأ href = "http://perldoc.perl.org/perlfaq7.html#How-can-I-pass٪2freturn-a-٪7bFunction٪2c-FileHandle٪2c-Array٪2c -Hash٪ 2C-طريقة٪ 2C-التعبيرات المنتظمة٪ 7D٪ 3F "يختلط =" noreferrer "> كيف يمكنني تمرير / إرجاع {وظيفة، FileHandle، مجموعة، تجزئة، الطريقة، التعبيرات المنتظمة}؟

نصائح أخرى

وتعمل هذه التعليمة البرمجية:

#!/bin/perl -w

use strict;

sub PrintAA
{
    my($test, %aa) = @_;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
    }
}

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );

PrintAA("test", %hash);

والنقطة الأساسية هي استخدام سياق مجموعة في 'بيان' بلدي () في وظيفة.


<اقتباس فقرة>   

وماذا الأعمال سياق مجموعة فعلا؟

وباختصار مفيد، فإنه يجعل من العمل بشكل صحيح.

وهذا يعني أن يتم تعيين القيمة الأولى في مجموعة @_ من الحجج ل$test، ويتم تعيين العناصر المتبقية إلى %aa التجزئة. نظرا للطريقة دعوت عليه، هناك عدد فردي من العناصر في @_، وذلك مرة واحدة تم تعيين العنصر الأول إلى $test، هناك عدد زوجي من المنتجات المتاحة لتعيين %aa، مع البند الأول من كل زوج كونها مفتاح ( 'أأأ'، 'BBB'، 'CCC' في بلدي على سبيل المثال)، والثاني هو القيمة المطابقة.

وسيكون من الممكن استبدال %aa مع @aa، وفي هذه الحالة، فإن مجموعة لديها 6 وحدات في ذلك. كما سيكون من الممكن استبدال %aa مع $aa، وفي هذه الحالة، فإن $aa متغير يحتوي على قيمة "AAA"، وسيتم تجاهل القيم المتبقية في @_ قبل التعيين.

إذا قمت بحذف الأقواس حول قائمة متغير، ترفض بيرل ترجمة التعليمات البرمجية. أظهرت إحدى الإجابات البديلة تدوين:

my $test = shift;
my(%aa) = @_;

وهذا هو الى حد كبير ما يعادل ما كتبته. الفرق هو أنه بعد البيانين my، @_ يحتوي فقط على 6 عناصر في هذا الاختلاف، في حين أن النسخة my واحد، فإنه لا يزال يحتوي على 7 عناصر.

وهناك بالتأكيد مسائل أخرى في <لأ href = "https://stackoverflow.com/questions/376921/what-is-the-difference-between-the-scalar-and-list-contexts-in-perl" > SO حول السياق مجموعة.


<اقتباس فقرة>   

في الواقع، لم أكن يسأل عن my($test, %aa) = @_; أنا كان يسأل عن my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); مقابل my %hash = { 'aaa' => 1, ... };

والفرق هو أن {...} تدوين يولد المرجع التجزئة و(...) تدوين يولد القائمة، التي تقوم بتعيين إلى تجزئة (بدلا من تجزئة المرجع). وبالمثل، [...] يولد المرجع مجموعة وليس صفيف.

والواقع، قم بتغيير رمز 'الرئيسي' بحيث يقرأ: بلدي (٪ التجزئة) = {...}؛ وتحصل على وقت التشغيل (ولكن ليس وقت الترجمة) خطأ - أرقام الأسطر علاج بحذر منذ واضاف لقد التشفيرات بديلة لملفي:

Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.

وبدلا من ذلك:

sub PrintAA
{
    my $test       = shift;
    my %aa         = @_;
        print $test . "\n";
        foreach (keys %aa)
        {
                print $_ . " : " . $aa{$_} . "\n";
                $aa{$_} = $aa{$_} . "+";
        }
}

والشيء كنت في عداد المفقودين في الأساس هو أن مجموعة النقابي ليست حجة واحدة (على الرغم من اشارة مجموعة النقابي هو، كما هو الحال في الجواب بول Tomblin ل).

ويبدو أنك يجب أن تمر في اشارة الى تجزئة.

sub PrintAA
{
   my $test = shift;
   my $aa = shift;
   if (ref($aa) != "HASH") { die "bad arg!" }
   ....
}

PrintAA($foo, \%bar);

والسبب لا يمكنك القيام

my %aa = shift;

ولأن بيرل يسطح كل الحجج لروتين في قائمة واحدة،_. يتم نسخ كل عنصر، لذلك يمر في بالرجوع يتجنب تلك النسخ أيضا.

وكالعادة هناك عدة طرق. هنا هو ما <م> بيرل أفضل الممارسات ، أن معظم التبجيل مؤشرات النمط، أن يقول حول تمرير المعلمات إلى وظائف:

استخدام تجزئة الوسائط المسماة لأي روتين الذي يحتوي على أكثر من ثلاثة المعلمات

ولكن لأن لديك اثنين فقط، يمكن أن تحصل بعيدا؛) مع مرور بشكل مباشر مثل هذا:

my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);

func($scalar, %hash)

ويعرف وظيفة من هذا القبيل:

sub func {
    my $scalar_var = shift;
    my %hash_var = @_;

    ... Do something ...
}

ويمكن أن يكون أكثر فائدة إذا كنت قد تظهر بعض التعليمات البرمجية.

وجميع الطرق المذكورة أعلاه تعمل، ولكن هذا كان دائما الطريق فضلت أن تفعل أشياء من هذا القبيل:

sub PrintAA ($\%)
{
    my $test       = shift;
    my %aa         = ${shift()};
    print "$test\n";
    foreach (keys %aa)
    {
        print "$_ : $aa{$_}\n";
        $aa{$_} = "$aa{$_}+";
    }
}

ملحوظة: أنا أيضا تغيرت التعليمات البرمجية الخاصة بك قليلا. سلاسل بيرل نقلت المزدوج وتفسير "$test" إلى أن تكون قيمة $test بدلا من '$test' سلسلة الفعلية، لذلك لا تحتاج إلى أن العديد .s.

وأيضا، كنت مخطئا حول كيفية عمل النماذج. لتمرير تجزئة، استخدم هذا:

PrintAA("test", %hash);

لطباعة إشارة التجزئة، استخدم هذا:

PrintAA("test", %$ref_to_hash);

وبطبيعة الحال، الآن لا يمكنك تعديل تجزئة المشار إليه بواسطة $ref_to_hash لأنك تقوم بإرسال نسخة، ولكن يمكنك تعديل %hash الخام لأنك تمرير فإنه كمرجع.

وسيطات إلى وظائف الحصول على بالارض في مجموعة واحدة (_). ذلك انها عادة ما تكون أسهل لتمرير التجزئة إلى وظيفة حسب المرجع.

لإنشاء HASH:

my %myhash = ( key1 => "val1", key2 => "val2" );

لإنشاء إشارة إلى أن HASH:

my $href = \%myhash

لوصول إلى هذه التجزئة بالرجوع؛

%$href

وحتى في الفرعي الخاص بك:

my $myhref = shift;

keys %$myhref;

وجميع ردود أخرى هنا يبدو حتى الآن معقدة الى حد ما بالنسبة لي. عندما أكتب بيرل وظيفة وعادة ما "توسيع" كل الحجج مرت في السطر الأول من الدالة.

sub someFunction {
    my ( $arg1, $arg2, $arg3 ) = @_;

وهذا يشبه إلى لغات أخرى، حيث تقوم بتعريف الوظائف ك

... someFunction ( arg1, arg2, arg3 )

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

sub testFunc {
    my ( $string, %hash ) = @_;
    print "$string $hash{'abc'} $hash{'efg'} $string\n";
}

my %testHash = (
    'abc' => "Hello",
    'efg' => "World"
);
testFunc('!!!', %testHash);

وكما هو متوقع إخراج:

!!! Hello World !!!

وهذا يعمل يتم تمرير becaus في الحجج بيرل دائما على أنها مجموعة من القيم العددية وإذا كنت تمر التجزئة، انها تضاف قيمة المفتاح / أزواج إلى أن مجموعة. في العينة أعلاه، فإن الحجج التي تم تمريرها إلى وظيفة كما مجموعة (@_) هي في الواقع:

'!!!', 'abc', 'Hello', 'efg', 'World'

و "!!!" بسيط المخصصة ل%string، في حين %hash "يبتلع" كل الحجج الأخرى، دائما تفسير واحد كمفتاح واحد القادم كقيمة (حتى تستخدم كل عناصر متابعة).

وأنت لا يمكن أن تمر التجزئة متعددة بهذه الطريقة والتجزئة لا يمكن أن يكون الوسيطة الأولى، وإلا فإنه ابتلاع كل شيء، ويترك كل الحجج الأخرى غير المعينة.

وبطبيعة الحال بالضبط نفس يعمل من أجل مجموعة كحجة الماضية. والفرق الوحيد هنا هو أن صفائف لا تميز بين المفاتيح والقيم، بالنسبة لهم كل الحجج التي خلفتها هي القيم ومجرد الحصول على دفع لمجموعة.

استخدم الفرعية معلمات أكثر للحصول على تجزئة أو hashref - مهما مرت :)

sub get_args { ref( $_[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
  my $test = shift;
  my $aa = get_args(@_);;
  #then
  $aa->{somearg} #do something
  $aa->{anotherearg} #do something

}

وظيفة اتصل بك مثل هذا:

printAA($firstarg,somearg=>1, anotherarg=>2)

وأو ما شابه ذلك (بغض النظر):

printAA($firstarg,{somearg=>1, anotherarg=>2})

وأو حتى مثل هذا (بغض النظر):

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );

PrintAA("test", %hash);

وهتاف!

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