Perl foreach loops

文章推薦指數: 80 %
投票人數:10人

A foreach loop runs a block of code for each element of a list. No big whoop, “perl foreach” continues to be one of the most popular on ... MORE: Togglenavigation Perl.com   ABOUT   AUTHORS   CATEGORIES #   TAGS Perlforeachloops Sep23,2018by briandfoy Aforeachlooprunsablockofcodeforeachelementofalist.Nobigwhoop,“perlforeach”continuestobeoneofthemostpopularonGooglesearchesforthelanguage.Sowethoughtwe’dseewhat’shappenedin20years.IexpandonTomChristiansen’sslidethat’spartofhislongerpresentationthenaddanewbutexperimentalfeatureattheend.Ifyouwantmore,there’splentytoreadinperlsynormybookLearningPerl. Goingthroughalist Unlessyousayotherwise,foreachaliasesthecurrentelementtothetopicvariable$_.Youcanspecifythatlistdirectlyintheparenthesesafterforeach,useanarrayvariable,orusetheresultofasubroutinecall(amongstotherwaystogetalist): foreach(1,3,7){ print"\$_is$_"; }my@numbers=(1,3,7); foreach(@numbers){ print"\$_is$_"; }subnumbers{return(1,3,7)} foreach(numbers()){ print"\$_is$_"; }subnumbers{keys%some_hash} foreach(numbers()){ print"\$_is$_"; } Somepeopleliketousethesynonymfor.There’saproperC-styleforthathasthreesemicolon-separatedpartsintheparentheses.IfPerldoesn’tseethetwosemicolonsittreatsforjustlikeaforeach: for(my$i=0;$i<5;$i++){#Cstyle print"\$iis$i"; } for(0..4){#foreachsynonym print"\$_is$_"; } Elementsourcegotchas Thealiasingisonlytemporary.Aftertheforeachthetopicvariablereturnstoitsoriginalvalue: $_="Originalvalue"; my@numbers=(1,3,7); print"\$_before:$_\n"; foreach(@numbers){ print"\$_is$_\n"; $_=$_*2; } print"\$_after:$_\n"; Theoutputshowsthat$_appearsunaffectedbytheforeach: $_before:Originalvalue $_is1 $_is3 $_is7 $_after:Originalvalue Thisisanaliasinsteadofacopy,whichisashortcutthatallowsyourprogramtobealittlefasterbynotmovingdataaround.Ifyouchangethetopicyouchangetheoriginalvalueifthelistsourceisanarray(thevaluesareread-onlyotherwiseandyou’llgetanerror): my@numbers=(1,3,7); print"Before:@numbers\n";#Before:137 foreach(@numbers){ print"\$_is$_\n"; $_=$_*2; } print"After:@numbers\n";#After:2614 Notonlythat,butifyouchangethesourcebyaddingorremovingelementsyoucanscrewuptheforeach.Thisloopsinfinitelyprocessingthesameelementbecauseeachgothroughtheblockmovesthearrayelementsoveroneposition;whentheiteratormovesontothenextpositionitfindsthesameoneitjustsaw: my@numbers=(1,3,7); print"\$numberbefore:$number\n"; foreach$number(@numbers){ print"\$numberis$number\n"; unshift@numbers,"Addedlater"; } Thisoutputwillgoonforever: $numberis1 $numberis1 $numberis1 $numberis1 Namingyourowntopicvariable The$_isoftenhandybecauseit’sthedefaultvariableforseveralPerlfunctions,suchaschomporsplit.Youcanuseyourownnamebyspecifyingascalarvariablebetweentheforeachandtheparentheses.Usuallyyoudon’twanttousethatvariableforsomethingotherthantheloopsotheusualstyledeclaresitinlinewiththeforeach: foreachmy$number(1,3,7){ print"\$numberis$number"; } SincePerlflattenslistsintoonebiglist,youcanusemorethanonelistsourceintheparentheses: my@numbers=(1,3,7); my@more_numbers=(5,8,13); foreachmy$number(@numbers,@more_numbers){ print"\$numberis$number"; } Oramixofsourcetypes: my@numbers=(1,3,7); my@more_numbers=(5,8,13); foreachmy$number(@numbers,numbers(),keys%hash){ print"\$numberis$number"; } Usingyourownnamedtopicvariableactsjustlikewhatyousawwith$_: my@numbers=(1,3,7); my$number='Originalvalue'; say"Before:$number"; foreach$number(@numbers){ say"\$numberis$number"; } say"After:$number"; Theoutputshowsthealiasingeffectandthattheoriginalvalueisrestoredaftertheforeach: Before:Originalvalue $numberis1 $numberis3 $numberis7 After:Originalvalue Controlling Therearethreekeywordsthatletyoucontroltheoperationoftheforeach(andotherloopingstructures):last,next,andredo. Thelaststopsthecurrentiteration.It’sasifyouimmediatelygopastthelaststatementintheblockthenbreaksoutoftheloop.Itdoesnotlookatthenextitem.Youoftenusethiswithapostfixconditional: foreach$number(0..5){ say"Starting$number"; lastif$number>3; say"\$numberis$number"; say"Ending$number"; } say'Pasttheloop'; Youstarttheblockforelement3butendtheloopthereandcontinuetheprogramaftertheloop: Starting0 $numberis0 Ending0 Starting1 $numberis1 Ending1 Starting2 $numberis2 Ending2 Starting3 Pasttheloop Thenextstopsthecurrentiterationandmovesontothenextone.Thismakesiteasytoskipelementsthatyoudon’twanttoprocess: foreachmy$number(0..5){ say"Starting$number"; nextif$number%2; say"\$numberis$number"; say"Ending$number"; } Theoutputshowsthatyouruntheblockwitheachelementbutonlytheevennumbersmakeitpastthenext: Starting0 $numberis0 Ending0 Starting1 Starting2 $numberis2 Ending2 Starting3 Starting4 $numberis4 Ending4 Starting5 Theredorestartsthecurrentiterationofablock.Youcanuseitwithaforeachalthoughit’smorecommonlyusedwithloopingstructuresthataren’tmeanttogothroughalistofitems. Here’sanexamplewhereyouwanttogetthree“good”linesofinput.Youiteratethroughthenumberoflinesthatyouwantandreadstandardinputeachtime.Ifyougetablankline,yourestartthesameloopwith my$lines_needed=3; my@lines; foreachmy$animal(1..$lines_needed){ chomp(my$line=); redoif$line=~/\A\s*\z/x;#skip"blank"lines push@lines,$line; } say"Linesare:\n\t",join"\n\t",@lines; Theoutputshowsthattheloopeffectivelyignoretheblanklinesandgoesbacktothetopoftheloop.Itdoesnotusethenextiteminthelistthough.Aftergettingablanklinewhenittriestoreadthesecondline,ittriesthesecondlineagain: Readingline1 Firstline Readingline2 Readingline2 Readingline2 Secondline Readingline3 Readingline3 Readingline3 Thirdline Linesare: Firstline Secondline Thirdline That’snotveryPerlythoughbutthisisanarticleaboutforeach.Abetterstylemightbetoreadlineswithwhiletothepointthat@linesislargeenough: my$lines_needed=3; my@lines; while(){ nextif/\A\s*\z/x; chomp; push@lines,$_; lastif@lines==$lines_needed; } say"Linesare:\n\t",join"\n\t",@lines; There’smorethatyoucandowiththese.Theworkwithlabelsandnestedloops.YoucanreadmoreabouttheminperlsynorLearningPerl. Acommonfile-readinggotcha Sinceforeachgoesthrougheachelementofalist,somepeoplereachforitwhentheywanttogothrougheachlineinafile: foreachmy$line(){...} Thisisusuallynotagoodidea.Theforeachneedstohavetoentirelistallatonce.Thisisn’talazyconstructlikeyou’dseeinsomeotherlanguages.Thismeansthattheforeachreadsinallofstandardinputbeforeitdoesanything.And,ifstandardinputdoesn’tclose,theprogramappearstohang.Orworse,ittriestocompletelyreadterabytesofdatafromthatfilehandle.Memoryischeap,butnotthatcheap. Asuitablereplacementisthewhileidiomthatreadsandprocessesonelineatatime: while(){...} Thisisreallyashortcutforanassignmentinscalarcontext.Thatreadsonlyonelinefromthefilehandle: while(defined($_=)){...} Anexperimentalconvenience Perlv5.22addedanexperimentalrefaliasingfeature.Assigningtoareferencemakesthethingontherightanaliasforthethingontheleft.Here’sasmalldemonstrationwhereyouassignananonymoushashtoareferencetoanamedhashvariable.Now%hisanothername(thealias)forthathashreference: usefeatureqw(refaliasing); useData::Dumper; \my%h={qw(a1b2)}; sayDumper(\%h); Thisishandyinaforeachwheretheelementsofthelistarehashreferences.First,here’showyoumightdothiswithoutthefeature.Insidetheblockyouinteractthe$hashasareference;youmustdereferenceittogettoavalue: my@mascots=( { type=>'camel', name=>'Amelia', }, { type=>'butterfly', name=>'Camelia', }, { type=>'go', name=>'GoGopher', }, { type=>'python', name=>'Monty', }, );foreachmy$hash(@mascots){ say$hash->{'name'} } Withv5.22’srefaliasingfeatureyoucanuseanamedhashvariableasthetopic.Insidetheblockyouinteractwiththecurrentelementasanamedhash.There’sno->foradereference: usev5.22; usefeatureqw(refaliasing); useData::Dumper; my@mascots=( { type=>'camel', name=>'Amelia', }, { type=>'butterfly', name=>'Camelia', }, { type=>'go', name=>'GoGopher', }, { type=>'python', name=>'Monty', }, ); foreach\my%hash(@mascots){ say$hash{'name'} } Theoutputisthesameinbothprograms: Amelia Camelia GoGopher Monty Aliasingviareferenceisexperimentalat... There’sawarningfromthisexperimentalfeature(and,allsuchfeatures).ThefeaturemightchangeorevendisappearaccordingtoPerl’sfeaturepolicy.Disablethewarningifyouarecomfortablewiththat: nowarningsqw(experimental::refaliasing); Conclusion Theforeachisahandywaytogothroughalistanelementatatime.Useitwhenyoualreadyhavethelistcompletelyconstructed(andnottoprocessafilehandle).Defineyourowntopicvariabletochooseadescriptivename. Tags syntax foreach loop refaliasing briandfoy briandfoyisaPerltrainerandwriter,andasenioreditoratPerl.com.He’stheauthorofMasteringPerl,MojoliciousWebClients,LearningPerlExercises,andco-authorofProgrammingPerl,LearningPerl,IntermediatePerlandEffectivePerlProgramming. Browsetheirarticles Feedback Somethingwrongwiththisarticle?HelpusoutbyopeninganissueorpullrequestonGitHub Tweetsbyperlfoundation



請為這篇文章評分?