
- TOP
- ã¿ã°äžèЧ
- Perl
Perl
ã€ãã³ã
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã
ãã¬ãžã³
æè¡ããã°
LifeKeeperã®ãå°ã£ããããã§ããïŒãã«å€ããïŒãµããŒãäºäŸããåŠã¶ãã©ãã«ã·ã¥ãŒãã£ã³ã°ïŒåçºé²æ¢ç ããã«ã¡ã¯ãSCSKã®åç°ã§ãã ãã€ã TechHarmony ãã芧ããã ãããããšãããããŸãã ã·ã¹ãã ã®ãªãã¬ãŒã¹ãããŒããŠã§ã¢æŽæ°ã®ã¿ã€ãã³ã°ã§èšªããããããã«ãŠã§ã¢ã®ããŒãžã§ã³ã¢ãããã ããµããŒãåãïŒEOSïŒå¯Ÿå¿ãããé
åçãªæ°æ©èœã®è¿œå ããªã©ãOSã®ãããé©çšãšã¯ãŸãéã£ããæåŸ
ãšç·åŒµãå
¥ãæ··ããäžå€§ã€ãã³ãã§ã¯ãªãã§ããããã ããããHAã¯ã©ã¹ã¿ãŒãœãããŠã§ã¢ã§ããLifeKeeperã«ãããŠããã®ãããŒãžã§ã³ã¢ãããã¯åãªããã¡ã€ã«ã®çœ®ãæãã§ã¯ãããŸããã ãã€ã³ã¹ããŒã©ãŒãå®è¡ããŠãããŒãžã§ã³çªå·ãäžããã°å®äºïŒã âŠâŠããæã蟌ãã§äœæ¥ãé²ããçµæãåèµ·ååŸã«èšå®ãã¡ã€ã«ãåæå€ã«æ»ã£ãŠããããé·å¹ŽåããŠããã¹ã¯ãªãããçªç¶ãšã©ãŒãåãå§ããããšãã£ããäºæãã¬ãã©ãã«ã«çŽé¢ããããšããããŸãã æ¬é£èŒäŒç»ãLifeKeeper ã®ãå°ã£ããããã§ããïŒãã«å€ããïŒãµããŒãäºäŸããåŠã¶ãã©ãã«ã·ã¥ãŒãã£ã³ã°ïŒåçºé²æ¢çãã§ã¯ããµããŒãã»ã³ã¿ãŒã«èç©ããããçã®ãã©ãã«äºäŸããå
ã«ãå®å®éçšã®ããã®å®è·µçãªç¥æµãå
±æããŠãããŸãã ã¯ããã«ïŒæåãžã®ããŒãããããæã é£èŒç¬¬2åãšãªãä»åã¯ãLifeKeeperæ¬äœãDataKeeperã®ããŒãžã§ã³ã¢ããã«çŠç¹ãåœãŠãŸãã ããŒãžã§ã³ã¢ããäœæ¥ã«ãããŠãæãæãã®ã¯ ãèŠããªãå€åã ã§ãã ã€ã³ã¹ããŒã©ãŒã¯äŸ¿å©ã§ããããããè£åŽã§ã©ã®èšå®ãåŒãç¶ããã©ã®èšå®ããªã»ããããã®ãããŸãæ°ããããŒãžã§ã³ãå€ãèšå®ãã©ãè§£éããã®ãã¯ããªãªãŒã¹ããŒãã®çްéšãèªã¿èŸŒãŸãªãéãèŠããŠããŸããã ä»åã¯ãå®éã«ãµããŒããžå¯ãããããããŒãžã§ã³ã¢ãã倱æäºäŸãã以äžã®3ã€ã®ãèœãšã穎ïŒTrapïŒãã«åé¡ããŸããã èšå®ãšç°å¢ã®ããµã€ã¬ã³ãå€åã éå»ã®ããŸããããããçããã è¿éã¯ãæ¥ãã°åãã ãããã®äºäŸããããªã倱æããã®ãããåŠã³ã確å®ã«æåãããããã®ãã§ãã¯ãã€ã³ãïŒããŒããããïŒã解説ããŸãã ãã®ä»ã®é£èŒäŒç»ã¯ä»¥äžã®ãªã³ã¯ããã©ããïŒ ããªãœãŒã¹èµ·åã»ãã§ã€ã«ãªãŒããŒå€±æã®æ·±å±€ #1ãEC2ãªãœãŒã¹ãèµ·åããªãïŒã¯ã©ãŠã飿ºã®ç²ç¹ãšãããã°è¡ â TechHarmony ããªãœãŒã¹èµ·åã»ãã§ã€ã«ãªãŒããŒå€±æã®æ·±å±€ #2ããã¡ã€ã«ã·ã¹ãã ã®æãã¬èœãšã穎ïŒãšã©ãŒã³ãŒãããåå ãèªã¿è§£ã â TechHarmony ããªãœãŒã¹èµ·åã»ãã§ã€ã«ãªãŒããŒå€±æã®æ·±å±€ #3ãèšå®ãã¹ã»éä¿¡é害ã»ããŒãžã§ã³éãã®æ·±å±€ãšåçºé²æ¢ç â TechHarmony ãOSã»LKããŒãžã§ã³ã¢ããã§æ³£ããªãããã« #1ãOSããŒãžã§ã³ã¯å€ããŠããªãã®ã«ïŒïŒã«ãŒãã«æŽæ°ã®ãèœãšã穎ããšäºææ§ã®çå® â TechHarmony ãå®é²ãLifeKeeperããŒãžã§ã³ã¢ããã®ãå°ã£ãïŒãäºäŸãã¡ã€ã« ããããã¯ãå®éã®ãµããŒãåãåãããããŒã¹ã«ããã±ãŒã¹ã¹ã¿ãã£ã§ãã ãèªåã®ç°å¢ã§ãèµ·ãããããããããªãã ãšããèŠç¹ã§ã芧ãã ããã Trap 1ïŒèšå®ãšç°å¢ã®ããµã€ã¬ã³ãå€åã ããŒãžã§ã³ã¢ããã«ãã£ãŠãä»ãŸã§äœ¿ã£ãŠããèšå®ãç°å¢ã ãéãã«ã å€ãã£ãŠããŸã ã±ãŒã¹ã§ãã â ã±ãŒã¹AïŒã¢ããããŒããããèšå®ãæ¶ããïŒïŒïŒLinuxçïŒ ãv9.5.2ããv9.9.1ãžã¢ããããŒãããŸããããšã©ãŒãªãå®äºããã®ã§ãããåèµ·ååŸã«ãªãããããã·èšå®ãªã©ãå¹ããªããªã£ãŠããŸãâŠã çºçç¶æ³: ã¢ããããŒãäœæ¥èªäœã¯æåãããã®ã®ãLifeKeeperã®åäœèšå®ãã¡ã€ã«ïŒ /etc/default/LifeKeeper ïŒã«èšè¿°ããŠããã«ã¹ã¿ã èšå®ãæ¶å€±ããŠããŸããã åå : LifeKeeperã®ä»æ§ã«ãããæŽæ°ã€ã³ã¹ããŒã«æã« äžéšã®èšå®ãã¡ã€ã«ãããã©ã«ãå€ã«æ»ãïŒäžæžããããïŒ æåãšãªã£ãŠããŸããã æèš: ãèšå®ã¯ãã¹ãŠèªåçã«åŒãç¶ãããã¯ãããšããæã蟌ã¿ã¯å±éºã§ããç¹ã«ã¡ãžã£ãŒããŒãžã§ã³ããŸããæŽæ°ã§ã¯ãããã¯ã¢ãããšåŸ©å
æé ãå¿
é ã§ãã â ã±ãŒã¹BïŒã¹ã¯ãªãããåããªãïŒPerlã®çœ ïŒWindowsçïŒ ãv8.9ããv8.10.2ãžäžããããšããŠããŸãããã©ã¡ãŒã¿å€æŽã¯äžèŠãšèããŸããããæ¬åœã«ãã®ãŸãŸäžããŠå€§äžå€«ã§ããããïŒã ãªã¹ã¯: 調æ»ã®çµæãLifeKeeperã«å梱ãããŠããPerlã®ããŒãžã§ã³ããv8.10.1以éã§ã5.8ç³»ãããã5.32ç³»ããžãšäžæ°ã«ã¢ããã°ã¬ãŒããããŠããããšã倿ããŸããã æèš: GenericãªãœãŒã¹ãªã©ã§Perlã¹ã¯ãªããã䜿çšããŠããå Žåãèšèªä»æ§ã®å€æŽã«ããã¹ã¯ãªãããåäœããªããªãå¯èœæ§ããããŸããã¢ããªã±ãŒã·ã§ã³ã ãã§ãªããããã«ãŠã§ã¢ãäŸåãã ãèšèªç°å¢ãã®å€å ãéèŠãªãã§ãã¯ãã€ã³ãã§ãã Trap 2ïŒéå»ã®ããŸããããããçããã å€ãããŒãžã§ã³ã§ã¯èš±å®¹ãããŠããïŒãããã¯ç¡èŠãããŠããïŒèšå®ã®äžåããæ°ããããŒãžã§ã³ã®ã峿 Œãªãã§ãã¯ãã«ãã£ãŠãšã©ãŒãšããŠé¡åšåããã±ãŒã¹ã§ãã â ã±ãŒã¹CïŒäº¡éIPãã¢ã©ãŒããåŒãèµ·ãã ãOSãšLifeKeeperãæŽæ°ããåŸããã°ã« failed quickCheck due to ALRM signal ãšãããšã©ãŒãå€çºããããã«ãªããŸããã以åã¯åºãŠããªãã£ãã®ã§ããâŠã åå : IPãªãœãŒã¹ã®ç£èŠãªã¹ãïŒ pinglist ïŒã«ãæ¢ã«æ€å»æžã¿ã§çéã§ããªãå€ãIPã¢ãã¬ã¹ãæ®ã£ãŠããŸããã ãªãä»ïŒ: ããŒãžã§ã³ã¢ããã«äŒŽã ãã§ãã¯åŠçããªãã©ã€ã®æåãå€åïŒå³æ ŒåïŒ ããå€ãIPãžã®å¿çåŸ
ã¡ãç©ã¿éãªã£ãçµæãã¿ã€ã ã¢ãŠãïŒALRM signalïŒãçºçããŠããŸããã æèš: ãä»ã¯äœ¿ã£ãŠããªããã©æ®ã£ãŠããèšå®ãã¯ãããŒãžã§ã³ã¢ããæã®æå€§ã®æµã§ããæŽæ°äœæ¥ã¯ãŽãæé€ã®çµ¶å¥œã®æ©äŒãšæããŸãããã â ã±ãŒã¹DïŒãã£ã¹ã¯ã«ååããªãïŒïŒïŒUUIDåé¡ïŒ ãããŒãžã§ã³ã¢ããåŸãDataKeeperãªãœãŒã¹ã§ãäžæã®èå¥åããªãããšããèŠåãåºãããããŒãã£ã·ã§ã³æ
å ±ãæ£ããååŸã§ããªããªããŸããã åå : LifeKeeper/DataKeeperã®æ°ããããŒãžã§ã³ã§ã¯ããã£ã¹ã¯ãäžæã«ç¹å®ããããã« ãUUIDãã®äœ¿çšãå¿
é åïŒãŸãã¯å³æ ŒåïŒ ãããŸãããå€ãç°å¢ã§ãMBR圢åŒãã®ããŒãã£ã·ã§ã³ã䜿ã£ãŠãããããUUIDãæãããæ°ããããŒãžã§ã³ã®èŠä»¶ãæºãããªããªã£ãŠããŸããã æèš: ãœãããŠã§ã¢ã®é²åã«åãããŠãã€ã³ãã©åŽïŒããŒãã£ã·ã§ã³ããŒãã«çïŒãGPT圢åŒãžã®ã¢ãã³åãå¿
èŠã«ãªãããšããããŸãã Trap 3ïŒè¿éã¯ãæ¥ãã°åãã æé ãçç¥ããããç¡çãªã¢ããããŒããã¹ãéãããšããŠå€±æããã±ãŒã¹ã§ãã â ã±ãŒã¹EïŒé£ã°ããããããŒãžã§ã³ã¢ãã ãv9.6.xããv9.8.1ãžäžæ°ã«ã¢ããããŒãããããšããã倱æããŸããã2äžä»£åããã®æŽæ°ã¯ãµããŒããããŠããã¯ãã§ããâŠã åå : åºæ¬çã«ã¯çŽæ¥ã¢ããããŒããå¯èœã§ããã ãã®ç¹å®ã®ããŒãžã§ã³ïŒv9.8.1ïŒã«ãããŠã¯ å
éšããã±ãŒãžã®å€§å¹
ãªæ§æå€æŽ ããã£ããããäŸå€çã«v9.7ãv9.8.0ãçµç±ãããã¹ãããã¢ããã°ã¬ãŒãããå¿
èŠã§ããã æèš: ããã€ãã®ã«ãŒã«ïŒN-2ãŸã§OKãªã©ïŒãä»åãé©çšãããããšã¯éããŸããããªãªãŒã¹ããŒãã«ã¯å¿
ã ãã¢ããã°ã¬ãŒãã®æ³šæç¹ãããäŸå€çãªãã¹ã ãèšèŒãããŠããŸãã®ã§ãæ
£ããŠããäœæ¥ã§ãå¿
ãç®ãéããŸãããã â ã±ãŒã¹FïŒGUIã®è¡šç€ºããããã ãDataKeeperæŽæ°åŸãGUIäžã§ãžã§ãæ
å ±ã衚瀺ãããªããªããŸããã 解決ç: 調æ»ã®çµæãå
éšæ
å ±ã®äžæŽåãèµ·ããŠããŸããããã®ã±ãŒã¹ã§ã¯ãç¡çã«ä¿®æ£ããããããåã€ã³ã¹ããŒã«ããŠãžã§ããåäœæãããæ¹ããçµæãšããŠæ©ãã確å®ã«è§£æ¶ããŸããã æèš: ããŒãžã§ã³ã倧ããé¢ããŠããå Žåãæåãããããå Žå ã¯ãäžæžãã¢ããããŒãã«åºå·ãããèšå®ããã¯ã¢ããããšã£ãäžã§ã®ãäœãçŽãïŒåäœæïŒããæçã«ãŒãã«ãªãããšããããŸãã ãåçºãããªãïŒãæåãžã®ãã§ãã¯ãªã¹ã äžèšã®å€±æäºäŸããå°ãåºãããããŒãžã§ã³ã¢ããäœæ¥åã«ç¢ºèªãã¹ãã転ã°ã¬å
ã®æããã§ãã¯ãªã¹ãã§ããèšç»æ®µéã§ãã²ã掻çšãã ããã â LifeKeeper/DataKeeper ããŒãžã§ã³ã¢ããäºå確èªã·ãŒã [ã ] ããã¹ã®ç¢ºèªã çŸåšã®ããŒãžã§ã³ããã¿ãŒã²ããããŒãžã§ã³ãžãçŽæ¥ãã¢ããããŒãå¯èœã§ããïŒïŒäžç¶ããŒãžã§ã³ãå¿
èŠãããŸãããïŒïŒ [ ã] ãèšå®ãã¡ã€ã«ã®ããã¯ã¢ããã æŽæ°æã«åæåããããã¡ã€ã«ïŒ /etc/default/LifeKeeper çïŒãç¹å®ããŠããŸããïŒ ãããã®æåããã¯ã¢ãããååŸããæŽæ°åŸã«åŸ©å
ããæé ãçµã¿èŸŒã¿ãŸãããïŒ [ ã] ãèšèªã»ç°å¢ã®å·®ç°ã PerlãPythonãªã©ãLifeKeeperãå©çšããã©ã³ã¿ã€ã ã®ããŒãžã§ã³ã«å€æŽã¯ãããŸãããïŒïŒèªäœã¹ã¯ãªãããžã®åœ±é¿ç¢ºèªïŒ ãã£ã¹ã¯ã®ããŒãã£ã·ã§ã³åœ¢åŒã¯æ°ããããŒãžã§ã³ã®èŠä»¶ïŒUUIDå¿
é /GPTæšå¥šãªã©ïŒãæºãããŠããŸããïŒ [ ã] ãäžèŠèšå®ã®åé€ïŒãŽãæé€ïŒã IPãªãœãŒã¹ã® pinglist ã«ãçŸåšçéã§ããªãã亡éIPããæ®ã£ãŠããŸãããïŒ [ã ] ãOSãšã®æŽåæ§ã OSèªäœã®ã«ãŒãã«ã¢ããããŒããè¡ãå ŽåãLifeKeeperã®åã€ã³ã¹ããŒã«ãã¢ãžã¥ãŒã«åã³ã³ãã€ã«ã®æé ã確èªããŸãããïŒ [ã ] ããªã«ããªãã©ã³ã æŽæ°ã€ã³ã¹ããŒã«ãäžæŽåãèµ·ãããå Žåã«åããäžåºŠã¢ã³ã€ã³ã¹ããŒã«ããŠãæ°èŠã€ã³ã¹ããŒã«ïŒèšå®åŸ©å
ïŒãŸãã¯åäœæïŒãã«åãæ¿ããå€æåºæºãæã£ãŠããŸããïŒ ãã¹ããã©ã¯ãã£ã¹ïŒæåãžã®è¿é ãã©ãã«ãé²ãããã«ãææ¥ããã§ããããã¹ããã©ã¯ãã£ã¹ãã3ã€ææ¡ããŸãã ããªãªãŒã¹ããŒããã¯å®ã®å°å³ ãªãªãŒã¹ããŒããããã°ä¿®æ£ã®ãªã¹ããã ãšæã£ãŠããŸãããïŒ æ¬åœã«èŠãã¹ãã¯ãå¶éäºé
(Known Issues)ã ãš ã倿Žç¹ (Migration/Changes)ãã§ããããã«ã¯ãèšå®ãã¡ã€ã«ãåæåãããããUUIDãå¿
é ã«ãªãããšãã£ãéèŠæ
å ±ãå¿
ãæžãããŠããŸãã ã¹ããŒãžã³ã°ç°å¢ã§ã®ãªããŒãµã«ã¯å¿
é æºäžã®ç¢ºèªã ãã§ã¯ããpinglistã®ã¿ã€ã ã¢ãŠããããPerlã®äºææ§ããšãã£ãç°å¢äŸåã®ãã©ãã«ã¯èŠæããŸãããæ¬çªç°å¢ã®ã¯ããŒã³ïŒãŸãã¯åçæ§æïŒãçšæããå®éã«ããŒãžã§ã³ã¢ããæé ãæµããªããŒãµã«ãè¡ã£ãŠãã ããã 倧å¹
ãªæŽæ°ã¯ãåäœæããèŠéã« æ°å¹Žåã®ããŒãžã§ã³ããäžæ°ã«ææ°çã«ãããããªå Žåãç¶ãæ¥ãã®ã¢ããããŒããç¹°ãè¿ãããããèšå®æ
å ±ãæ§ããŠãã¯ãªãŒã³ã€ã³ã¹ããŒã«åŸã«åèšå®ãããæ¹ããæœåšçãªãŽããæ®ãããçµæçã«å®å®çšŒåã«ã€ãªããããšãå€ã
ãããŸãããäžæžããã«ãã ãããªãæè»æ§ãéèŠã§ãã ãŸãšã ããŒãžã§ã³ã¢ããæã®ãã©ãã«ã¯ãå€ãã®å Žåãæºåäžè¶³ãããæã蟌ã¿ãã®ééã«å
¥ã蟌ããã®ã§ãã ããããä»åã玹ä»ããäºäŸã®ããã«ãäºåã« ãäœãå€ããã®ãããäœãæ¶ããã®ãããä»ã®èšå®ã«ãŽãã¯ãªããã ã確èªããŠããã°ããã®ã»ãšãã©ã¯é²ããŸãã ãLifeKeeperã®ãå°ã£ããããã§ããïŒãã«å€ããã ä»åã®ããŒãããããåèã«ããã²å®å¿ã»å®å
šãªããŒãžã§ã³ã¢ããèšç»ãç«ãŠãŠãã ããã æ¬¡åäºå 次åããã¯æ°ç« ã«çªå
¥ïŒ ããŒãã¯ãã¯ã©ãŠãç°å¢ç¹æã®èœãšã穎ïŒAWS/Azure飿ºã§ããããã€ã³ããã§ãã ã¯ã©ãŠããªãã§ã¯ã®ããªã³ãã¬ãã¹ãšåãæèŠã§èšå®ãããåããªãïŒïŒããšãããã©ãã«ã ãã®ç¬¬äžåŒŸãšããŠã AWSç°å¢ã§ã®LifeKeeperå®å®çšŒåè¡ ã«ãã©ãŒã«ã¹ããŸãã ãRoute53ã®DNSãåãæ¿ãããªãïŒãã䟿å©ãªã¯ãã®ãAuto RecoveryããLifeKeeperãšå§å©ããïŒïŒããšãã£ãAWSç¹æã®äºäŸãšãEC2ã»S3飿ºã®æ³šæç¹ã培åºè§£èª¬ããŸãããæ¥œãã¿ã«ïŒ 詳ããå
容ããç¥ãã«ãªãããããã¯ã以äžã®ãããŒããSCSK LifeKeeperå
¬åŒãµã€ããŸã§
ããã«ã¡ã¯ããšã³ãžãã¢ã® id:mp0liiu ã§ãã éåžžã«é
ããªã£ãŠããŸããŸããããæšå¹Žã®7/4ã«Perlã®ææ°å®å®ããŒãžã§ã³ã§ãã5.42ããªãªãŒã¹ãããã®ã§æ°æ©èœã倿Žç¹ã«ã€ããŠãŸãšããŸãã source::encoding ãã©ã°ãã远å ãããããã©ã«ãã§æå¹ã« ã¹ã³ãŒãå
ã®ãœãŒã¹ã³ãŒãã«æåŸ
ããæåã³ãŒãã®æå®ããããã©ã°ã source::encoding ã远å ãããŸããã æå®ã§ããã®ã¯ ascii ãš utf8 ã®ã¿ã§ãã use source::encoding 'ascii' ãããšã¹ã³ãŒãå
ã®ãœãŒã¹ã³ãŒãã«éASCIIæåãååšããŠããå Žåãã³ã³ãã€ã«ãšã©ãŒãçºçããããã«ãªããŸãã use source::encoding 'utf8' 㯠use utf8 ãšåçã§ãã v5.41 以éã® feature bundle 1 ã§ã¯ããã©ã«ãã§ use source::encoding 'ascii' ãæå¹ã«ãªããŸãã åŸæ¥ã§ã¯æ¬¡ã®ããã« use utf8 ããŠããªãã®ã«éASCIIæåãæ±ããããªã³ãŒãã¯ããšã©ãŒã«ãªãããšãªãæå³ããŠããªãæåãããŠããŸãããšããããŸããã say length "ããããã" ; # æ¬åœã¯5æåã ã, use utf8 ããŠããªãã®ã§ 15 ãåºåããã use source::encoding 'ascii' ããããšã§ããã®ãããªã³ãŒãã¯ã³ã³ãã€ã«ãšã©ãŒã«ãªãã®ã§äºåã«æ°ã¥ãããšãã§ããããã«ãªããŸãã use v5.42 ; # use source::encoding 'ascii' ãæå¹ã«ãªã say length "ããããã" ; # ã³ã³ãã€ã«ãšã©ãŒ: Use of non-ASCII character 0xE3 illegal when 'use source::encoding "ascii"' ããããã¯æ¥æ¬èªãªã©éASCIIæåã䜿ãã³ãŒãã¯ãã¡ããš use utf8 ããŠããæžãããã«ããŸãããã ãªãã source::encoding 'ascii' ã¯ã³ã¡ã³ããPODã§ãéASCIIæåããããšã³ã³ãã€ã«ãšã©ãŒã«ãªãã®ã§æ³šæãå¿
èŠã§ãã __DATA__ , __END__ ã»ã¯ã·ã§ã³ä»¥éã«æžãåã«ã¯åé¡ãããŸããã any, all æŒç®åã®è¿œå List::Util ã® any, all ãšåãæåãããŸãã æŒç®åãšããŠå®è£
ãããŠããããã³ãŒããããã¯ã®ã¹ã¿ãã¯ãã¬ãŒã ãäœãããããé«éã«å®è¡ã§ãããšã®ããšã§ãããããã³ãããŒã¯ããããããšã£ãŠã¿ããšãã倧ããããã©ãŒãã³ã¹ã®å·®ã¯ãªããã®ã®ãã³ãŒããããã¯å
ã®åŠçããªã¹ãã®èŠçŽ æ°ã«ãã£ãŠã©ã¡ãã®æ¹ãããã©ãŒãã³ã¹ãããããå€ãã£ãŠããŸããŸããã ãªã®ã§ãã ããå Žåã¯èªåã§è©²åœéšåã®ããã©ãŒãã³ã¹ãèšæž¬ããããšãããããããŸãã åèãŸã§ã« List::Util ãšé¢æ°ãšæŒç®åãšã§ãããããã³ãããŒã¯ããšã£ãã®ã§åèã«ããŠã¿ãŠãã ããã keywordã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(any) Benchmark: running keyword_any, list_util_any for at least 1 CPU seconds... keyword_any: 2 wallclock secs ( 1.13 usr + 0.00 sys = 1.13 CPU) @ 495.58/s (n=560) list_util_any: 1 wallclock secs ( 1.11 usr + 0.00 sys = 1.11 CPU) @ 355.86/s (n=395) Rate list_util_any keyword_any list_util_any 356/s -- -28% keyword_any 496/s 39% -- keywordã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(all) Benchmark: running keyword_all, list_util_all for at least 1 CPU seconds... keyword_all: 1 wallclock secs ( 1.11 usr + 0.00 sys = 1.11 CPU) @ 503.60/s (n=559) list_util_all: 1 wallclock secs ( 1.04 usr + 0.00 sys = 1.04 CPU) @ 358.65/s (n=373) Rate list_util_all keyword_all list_util_all 359/s -- -29% keyword_all 504/s 40% -- List::Utilã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(any) Benchmark: running keyword_any, list_util_any for at least 1 CPU seconds... keyword_any: 2 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 16.04/s (n=17) list_util_any: 1 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 17.92/s (n=19) Rate keyword_any list_util_any keyword_any 16.0/s -- -11% list_util_any 17.9/s 12% -- List::Utilã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(all) Benchmark: running keyword_all, list_util_all for at least 1 CPU seconds... keyword_all: 1 wallclock secs ( 1.05 usr + 0.00 sys = 1.05 CPU) @ 16.19/s (n=17) list_util_all: 1 wallclock secs ( 1.06 usr + 0.00 sys = 1.06 CPU) @ 17.92/s (n=19) Rate keyword_all list_util_all keyword_all 16.2/s -- -10% list_util_all 17.9/s 11% -- ãã³ãããŒã¯ã«äœ¿çšããã³ãŒãã¯ãã¡ã use v5.42 ; use Benchmark qw( timethese cmpthese ) ; use List::Util (); use utf8 ; binmode STDOUT, ':encoding(UTF-8)' ; my @ary = ( 1 .. 1000000 ); say "keywordã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(any)" ; cmpthese( timethese(- 1 , +{ keyword_any => sub { use experimental qw( keyword_any ) ; any { $_ == 500 } @ary ; }, list_util_any => sub { List::Util::any { $_ == 500 } @ary ; }, }) ); print " \n " ; say "keywordã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(all)" ; cmpthese( timethese(- 1 , +{ keyword_all => sub { use experimental qw( keyword_all ) ; all { $_ < 500 } @ary ; }, list_util_all => sub { List::Util::all { $_ < 500 } @ary ; }, }) ); print " \n " ; say "List::Utilã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(any)" ; cmpthese( timethese(- 1 , +{ keyword_any => sub { use experimental qw( keyword_any ) ; any { $_ == @ary / 2 } @ary ; }, list_util_any => sub { List::Util::any { $_ == @ary / 2 } @ary ; }, }) ); print " \n " ; say "List::Utilã®ã»ããããã©ãŒãã³ã¹ãè¯ãå Žå(all)" ; cmpthese( timethese(- 1 , +{ keyword_all => sub { use experimental qw( keyword_all ) ; all { $_ < @ary / 2 } @ary ; }, list_util_all => sub { List::Util::all { $_ < @ary / 2 } @ary ; }, }) ); print " \n " ; ã¬ãã·ã«ã«ãªã¡ãœããã宣èšã§ããããã«ãªã£ã my sub ã®ããã« my method ã§ã¹ã³ãŒãå
ã§ã®ã¿åŒã³åºãããšã®ã§ãããã¬ãã·ã«ã«ãªã¡ãœããã宣èšã§ããããã«ãªããŸããã ãŸããã¬ãã·ã«ã«ã¡ãœãããåŒã³åºãããã®æŒç®å ->& ã远å ãããŸããã use v5.42 ; use experimental 'class' ; class Point { my method hoge { say "hoge" ; } method wrap { $self -> &hoge ; } } Point->new->wrap(); # hoge $self->&method 㯠method($self) ã®ç³è¡£æ§æã§ãã åãã¯ã©ã¹å
ã§ãã¹ã³ãŒããéãã°åŒã³åºãããšã¯ã§ããªãã§ãããç¶æ¿å
ã®ã¯ã©ã¹ããåŒã³åºãããšãã§ããŸããã switch æ©èœãšã¹ããŒããããã³ã°æŒç®åã®åé€ãç¡æéã®å»¶æã« Perl5.38 ã§éæšå¥šãšãªãã5.42ã§åé€äºå®ã ã£ãswitch æ©èœ(given-whenæ§æ)ãšã¹ããŒããããã³ã°æŒç®åã¯åé€ãç¡æéã«å»¶æãšãªãããããã䜿ã£ãŠãå®éšçæ©èœã§ããããšã®èŠåã¯çºçããªãããã«ãªããŸããã switchæ©èœã¯ããã©ã«ãã§ã¯ç¡å¹ã«ãªã£ãŠãããåå¥ã«æå¹ã«ããããv5.34 ãŸã§ã® feature bundle ã§æå¹ã«ãªããŸãã v5.35 以éã® feature bundle ã§ã¯ç¡å¹ã«ãªããŸãã { use v5.10 ; given ( 100 ) { when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } { use v5.36 ; given ( 100 ) { # syntax error when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } { use feature 'switch' ; given ( 100 ) { when ( $_ % 2 == 0 ) { print " $_ is even" ; } default { print " $_ is odd" ; } } } ã¹ããŒããããã³ã°ã¯ããã©ã«ãã§æå¹ã§ããã smartmatch æ©èœãšããŠæå¹/ç¡å¹ãåãæ¿ããããããã«ãªããŸããã v5.40 ãŸã§ã® feature bundle ã§ã¯æå¹ã«ãªã£ãŠãããv5.42 以éã§ã¯ç¡å¹ãšãªããŸãã { use v5.41 ; print 'A' ~~ [ 'A' .. 'D' ] ? 'Included' : 'Not included' ; # syntax error } { use feature 'smartmatch' ; print 'A' ~~ [ 'A' .. 'D' ] ? 'Included' : 'Not included' ; } ãããŸã§åŸæ¹äºææ§ã®ããã®ããšãèãããšåé€ãé£ããã£ãã®ã§æ®ããŠãããŠããããšããæããããã®ã§ããããswitchæ©èœãã¹ããŒããããã³ã°ãå€çšããã³ãŒããæžãã®ã¯ããããã§ããªãã§ãã ç¹ã«ã¹ããŒããããã³ã°ã¯ãªãã©ã³ãããšã®æåãèŠããã®ãé£ããã®ã§ãããŠãããã»ããè¯ãã§ãããã switchæ©èœã¯çŽæ¥æ¡ä»¶åŒãèšè¿°ãããªã©ã¹ããŒããããã³ã°ãå©çšããªãããã«äœ¿ãéãã«ãããŠã¯äœ¿çšããŠãåé¡ãªãããªãšæããŸããã ã ãšããŠã代æ¿ãšã㊠matchæ§æ ãææ¡ãããŠãããå®éšçå®è£
ãäœããåŸã
å®è£
ãããå¯èœæ§ãããã®ã§ãä»ãŸã§éãã³ãŒããæžãã®ãäžçªç¡é£ããªãšæããŸãã ãã£ãŒã«ã倿°ã® attribute :writer ã远å ã¯ã©ã¹æ§æã®ãã£ãŒã«ã倿°ã®å€ãæŽæ°ãã setter ãèªåçæãã attribute ã远å ãããŸããã ã¹ã«ã©å€æ°ã®ã¿å¯Ÿå¿ããŠããŸãã class Point { field $x :writer :param; field $y :writer :param; } my $p = Point->new( x => 20 , y => 40 ); $p->set_x ( 60 )->set_y( 100 ); # writerã¯ã€ã³ã¹ã¿ã³ã¹èªèº«ãè¿ãã®ã§ã¡ãœãããã§ãŒã³ãå¯èœ åŒæ°ãæå®ãããšæå®ããååã§ setter ãçæããŸãã Mooseç³»ã®ã¯ã©ã¹ãã«ããŒã®ã¢ã¯ã»ãµãšéã£ãŠãã£ãŒã«ãåãšååã®ã¢ã¯ã»ãµã§ getter / setter äž¡æ¹ãšããŠäœ¿ããããã«ã§ããªãã®ã§æ³šæãå¿
èŠã§ãã ããã±ãŒãžã®åºåãæåãšããŠã®ã¢ãã¹ãããã£ãç¡å¹ã«ã§ããããã«ãªã£ã Perlã§ã¯ããã±ãŒãžåã®åºåãæåã« :: ãå©çšããŸãããPerl4ã®é 㯠' ãå©çšããŠããããã®äºææ§ãä¿ã€ããPerl5ã«ãªã£ãŠããããã£ãš ' ãããã±ãŒãžåã®åºåãæåãšããŠå©çšã§ããããã«ãªã£ãŠããŸããã ' ãããã±ãŒãžåã®åºåãæåãšããŠå©çšããããšã¯ Perl5.38 ã§éæšå¥šãšãªãã Perl5.41.3 ã§äžæŠåé€ãããŸããããè°è«ã®åŸã«ããã©ã«ãã§ã¯åŸ©æŽ»ãããã©ã°ãã§æå¹/ç¡å¹ãåãæ¿ããããããã«ãªããŸããã 以äžã®ããã« apostrophe_as_package_separator æ©èœãšããŠæå¹/ç¡å¹ãåãæ¿ããããããã«ãªã£ãŠããŸãã use feature 'say' ; use POSIX; use feature 'apostrophe_as_package_separator' ; say $ POSIX' VERSION ; # $POSIX::VERSION ãšåã no feature 'apostrophe_as_package_separator' ; say $ POSIX' VERSION ; # ã³ã³ãã€ã«ãšã©ãŒ apostrophe_as_package_separator 㯠use v5.42 ã§ç¡å¹ã«ãªããŸãã use v5.42 ; say $ POSIX' VERSION ; # ã³ã³ãã€ã«ãšã©ãŒ chdir ã CORE:: åå空éã«è¿œå ããã ã³ã¢é¢æ°ãšååã®é¢æ°ãããã±ãŒãžå
ã«å®çŸ©ãããŠããéãææ§ããé¿ããŠåŒã¹ããã CORE:: ã«ããã€ãçµã¿èŸŒã¿é¢æ°ã远å ãããŠãã£ãŠãã®ã§ããããã®æµãã®1ã€ããšæãããŸãã äºé
æŒç®åã§å·Šé
ãåŠå®ãããã®ãäžèªç¶ãªå Žåã«èŠåãçºçããããã« !$x < $y ã®ãããªã³ãŒãããã£ããšããŠãæ¯èŒæŒç®åã§å·Šé
ãæ¬åœã«åŠå®ãããããšã¯ãŸããªããŠãéåžžã¯æ¡ä»¶åŒå
šäœãåŠå®ãããå Žåãå€ããšæããŸãã ãã®ãããªå Žåã«èŠåãçºçããããã«ãªããŸããã ! $x < $y # èŠåãçºç: Possible precedence problem between ! and numeric lt (<) æææŒç®å(=~ãªã©)ã cmp ã <=> 以å€ã®æ¯èŒæŒç®åãisaæŒç®åã§ãã®èŠåãçºçããããã§ãã ãã®ãããªå Žåã¯åŠå®ãããæŒç®åã䜿ããããã£ãã§åªå
é äœãæç€ºããããåªå
é äœã®äœãè«çåŠå®æŒç®å not ãå©çšããããã«ããŸãããã $x >= $y !( $x < $y ) not $x < $y builtin ã¢ãžã¥ãŒã«ã® indexed 颿°ã§é
åã®ã€ã³ããã¯ã¹ãšå€ã®çµã®ãªã¹ããçæãã2倿°ã®forã«ãŒãã§ã€ãã¬ãŒã·ã§ã³ããã³ãŒãã®ããã©ãŒãã³ã¹ãæ¹å Perl5.40ã§è¿œå ããããçµã¿èŸŒã¿é¢æ°ãæäŸãã builtin ã¢ãžã¥ãŒã«ã® indexed 颿°ãå©çšããããšã§ãé
åã®indexãšèŠçŽ ã®åæãæ¥œã«æžããããã«ãªã£ãŠããŸããã use v5.40 ; my @array = qw( red blue green ) ; for my ( $index , $value ) (indexed @array ) { say " $index => $value " ; } ãã ããããã¯é
åã®ã€ã³ããã¯ã¹ãšå€ã®ãªã¹ããå®éã«çæããç¹ãªã©ãéåžžã® for (@array) ã®ãããªã«ãŒãæãšæ¯ã¹ãŠå¹ççã§ãªãã³ãŒããšãªã£ãŠããŸããã 5.42ããã¯å
éšçã«ã¯é
åã®ã€ã³ããã¯ã¹ãšå€ã®ãªã¹ããå®éã«çæããã®ã§ã¯ãªããéåžžã® for (@array) ãšåãæ¹æ³ã§é
åãã€ãã¬ãŒã·ã§ã³ããããã«ãªããŸããã ãŸãšã source::encoding ãã©ã°ãã远å ããããšã¯åœ±é¿ã倧ãããã§ã use utf8 ããŠããªãããã«æžãããã³ãŒãã¯èŠçŽããã»ãããããããããŸããã ãã®ä»ã¯ä»åã现ããæ¹åç¹ãå€ããšãã£ãæãã§ãããPerlã«è¶³ããªãã£ãæ©èœã远å ããããPerl4ã®ããã®æ§æãç¡å¹ã«ã§ããããã«ãªã£ãããšç¢ºå®ã«éå»ã®ããŒãžã§ã³ãã䜿ãããããªã£ãŠããŸãã æ¬¡ã®ããŒãžã§ã³ã§ã¯ååä»ãåŒæ°ã远å ããããªã©ã倧ããªå€æŽãããããã§æ¥œãã¿ã§ãã ãã®èšäºã§ã¯æžããªãã£ãããšãããã®ã§è©³ããããšãæ°ã«ãªã£ãæ¹ã¯ å
¬åŒããã¥ã¡ã³ã ããã²èªãã§ã¿ãŠãã ããã use v5.42; ã®ãããªæ§æã®ããšã§ããPerlã§ã¯åŸæ¹äºææ§ãä¿ã€ããå€ãæ©èœã¯ç¡å¹ã«ã§ããããã«ãæ°ããæ©èœã¯æå¹ã«ã§ããããã«ãªã£ãŠããŸããã feature bundle ã¯ãããã£ãåæ©èœããããŒãžã§ã³ããšã«æšå¥šããããã®ããŸãšããŠæå¹/ç¡å¹ã«ããŠããããã©ã°ãã«ãªã£ãŠããŸãã ↩
äžäŒ.com Advent Calendar 2025 ã®25æ¥ç®ã®èšäºã§ãã äžäŒ.com ã¬ã¹ãã©ã³ã®éçºãæ
åœããŠããæ©ç° @takashi_onda ã§ãã æè¿ã¯ããŸãèãããããšã®ãªããã€ãããã¯ã¹ã³ãŒãã®è©±ãããŠã¿ãããšæããŸãã ã¯ããã« çŸä»£ã®ããã°ã©ãã³ã°èšèªã§ã¯ã¬ãã·ã«ã«ã¹ã³ãŒããããŸãã«åœããåã«ãªã£ãŠããŸã£ãŠããŠããã€ãããã¯ã¹ã³ãŒããšããæŠå¿µèªäœãèããããšããªãããšãã人ãå€ãã®ã§ã¯ãªãããšæããŸãã ããã°ã©ãã³ã°èšèªã®æŽå²ãåŠã¶éã«å°ãè§ŠããããŠããçšåºŠã§ãå®éãæå
ã®ãã³ã³ãã¥ãŒã¿ããã°ã©ãã³ã°ã®æŠå¿µã»ææ³ã»ã¢ãã«ããç¹ããŠã¿ãŠãã900ããŒãžè¿ã倧èã«ãããããããã€ãããã¯ã¹ã³ãŒãã«ã€ããŠã®èšåã¯1ããŒãžã«ãæºããªãã»ã©ã§ãã ãã®ããã«ãã€ãããã¯ã¹ã³ãŒãã¯æŽå²ã®äžã§æ¶ããŠãã£ãæŠå¿µã®ããã«èŠããŸããã§ãããçšèªãšããŠã¯å»ããäžæ¹ã§ã仿¥ã§ã䌌ãä»çµã¿èªäœãå®ã¯åçºæãããŠããŸããäœ¿ãæ¹ã«æ³šæã¯å¿
èŠã§ãããããŸãã¯ãŸããšæ¢åã³ãŒããžã®äŸµè¥²ãæå°ã«æããªããæèãäŒæãããææ®µãšããŠãä»ãæå¹ãªéžæè¢ã ããã§ã¯ãªãã§ããããã æ¬çš¿ã§ã¯ããã€ãããã¯ã¹ã³ãŒãã®æŽå²ãæ¯ãè¿ããªããããªãä»ã圢ãå€ããŠãã®èãæ¹ãåŒãç¶ãããŠããã®ããæèäŒæã®èгç¹ããèŠçŽããŠã¿ãããšæããŸãã ã¬ãã·ã«ã«ã¹ã³ãŒããšãã€ãããã¯ã¹ã³ãŒã ãŸãã¯å®çŸ©ã®ç¢ºèªããã¯ãããããšæããŸãã çŸä»£ã®ããã°ã©ãã³ã°èšèªã«ãããŠãç§ãã¡ãåœããåã®ããã«äº«åããŠããã®ãã¬ãã·ã«ã«ã¹ã³ãŒãïŒéçã¹ã³ãŒãïŒã§ãã const x = 'Global' ; function printX ( suffix ) { const prefix = 'value is ' console . log ( ` ${ prefix }${ x }${ suffix } ` ) ; } function withLocalX () { const x = 'Local' ; printX ( '!' ) ; } withLocalX () ; // -> 'value is Global!' printX ( '?' ) // -> 'value is Global?' ããã§ã printX ã«çŸãã倿°ã«æ³šç®ããŠãçšèª 1 ããµãã€ç޹ä»ããŸãã æçžå€æ°ïŒbound variableïŒ: 颿°ã®åŒæ°ïŒ suffix ïŒãå
éšã§ã®å®£èšïŒ prefix ïŒã«ãã£ãŠããã®å Žã§æå³ã確å®ãã倿°ãæããŸãã èªç±å€æ°ïŒfree variableïŒ: 颿°ã®äžã§å®£èšãåŒæ°å®çŸ©ããããŠããªã倿°ãæããŸãããã®äŸã§ã¯ x ãããã«ããããŸãã ã¬ãã·ã«ã«ã¹ã³ãŒããšãã€ãããã¯ã¹ã³ãŒãã®éãã¯ããã®èªç±å€æ°ãã©ã解決ãããã«ãããŸãã ã¬ãã·ã«ã«ã¹ã³ãŒãã®ã«ãŒã«ã¯ã·ã³ãã«ã§ããèªç±å€æ°ã®æå³ã¯é¢æ°ãå®çŸ©ãããå Žæã«ãã£ãŠéçã«æ±ºãŸãããšãããã®ã§ããäžã®äŸã§ã¯ printX ãå®çŸ©ãããå Žæã®å€åŽã«ããå€ 'Global' ãåç
§ãããŸããåŒã³åºãå
ã§ãã withLocalX ã®å
éšã«ååã®å€æ°ããã£ãŠããããã¯ç¡èŠãããŸãã ãã®æ§è³ªã«ãããç§ãã¡ã¯ã³ãŒãã®æ§é ãã倿°ã®ç±æ¥ãäžæã«èŸ¿ãããšãã§ãããšããæ©æµã«äžã£ãŠããŸãã ããããèªç¶ã«æãããããšæããŸãã ããŠãä»ååãäžãããã€ãããã¯ã¹ã³ãŒãïŒåçã¹ã³ãŒãïŒãèŠãŠã¿ãŸãããããã€ãããã¯ã¹ã³ãŒãã¯ãèªç±å€æ°ã®è§£æ±ºãã³ãŒãäžã®äœçœ®ã§ã¯ãªããå®è¡æã®åŒã³åºãã¹ã¿ãã¯ã«å§ããŸãã Perl ã® local å®£èš 2 ãäŸã«èŠãŠã¿ãŸãããã our $x = "Global" ; sub print_x { my ( $suffix ) = @_ ; my $prefix = "value is " ; print " $prefix$x$suffix \n " ; } sub with_local_x { local $x = "Local" ; print_x( "!" ); } with_local_x(); # -> "value is Local!" print_x( "?" ); # -> "value is Global?" print_x ãåŒã°ããéããã®èªç±å€æ° $x ã®å€ã¯èªåãåŒã³åºããŠããå®è¡æã®ã³ãŒã«ã¹ã¿ãã¯ã®ç¶æ
ã§æ±ºå®ãããŸãã with_local_x ã®äžã§ $x ãäžæçã«å€æŽãããŠãããã print_x ã¯ãã®å€ "Local" ãåºåããŸãããã㊠with_local_x ã®å®è¡ãçµããã°ããã®äžæçãªæçžãè§£é€ãã $x ã®å€ã¯ãµããã³ "Global" ãåç
§ãããããã«ãªããŸãã ãã€ãããã¯ã¹ã³ãŒãã®æŽå² çŸä»£ã®æèŠã§ã¯ããã€ãããã¯ã¹ã³ãŒãã¯äºæž¬äžèœã§äžç¢ºå®ãªãã®ã«èŠãããšæããŸããã§ã¯ããªããã®ãããªä»çµã¿ãçãŸããå©çšãããŠããã®ã§ããããããã®çµç·¯ãæ¯ãè¿ã£ãŠã¿ãããšæããŸãã å¯ç£ç©ãšããŠã®èªç ãã€ãããã¯ã¹ã³ãŒãã®èµ·æºã¯ã1950幎代åŸåã®åæã® Lisp ã«é¡ããŸãã åæã® Lisp ã«ãããŠãã€ãããã¯ã¹ã³ãŒãã¯ãæå³çã«èšèšãããæ©èœãšããããã¯ãçŽ æŽãªå®è£
ã®åž°çµã§ãããåœæã®ã€ã³ã¿ããªã¿ã«ãããŠå€æ°ã®å€ã解決ãããã£ãšãåçŽãªæ¹æ³ã¯ãå®è¡æã®ã·ã³ãã«ããŒãã«ïŒA-list ãšåŒã°ãã飿³ãªã¹ãïŒãã¹ã¿ãã¯ã®æ ¹å
ã«åãã£ãŠé ã«æ€çŽ¢ããããšã§ããã颿°ãå®çŸ©æã®ç°å¢ãšäžç·ã«ä¿æãããšããçºæ³ïŒåŸã«ã¯ããŒãžã£ãšåŒã°ãããã®ïŒã¯ãŸã ãªãããã®çŽ çŽãªå®è£
ããçµæãšããŠãã€ãããã¯ã¹ã³ãŒããçã¿åºããŸããã John McCarthy ã¯åŸã«ããã€ãããã¯ã¹ã³ãŒãããæå³ãã仿§ã§ã¯ãªãåãªãå®è£
äžã®ãã°ã§ããããããä¿®æ£ãããã ãããšèããŠãããšåæ³ããŠããŸã 3 ã åŒæ°ãã±ããªã¬ãŒã®åé¿çãšããŠã®å容 ãããããã®å¶ç¶ã®æåã¯å®çšäžã®å©äŸ¿æ§ããããããŸããã ããã°ã©ã ãè€éåãã颿°ã®åŒã³åºãéå±€ãæ·±ããªããšãæ«ç«¯ã®åŠçã§å¿
èŠã«ãªãèšå®å€ããã©ã°ãããã¹ãŠã®äžé颿°ã«åŒæ°ãšããŠæž¡ãç¶ããå¿
èŠãåºãŠããŸãããããããã±ããªã¬ãŒåé¡ã§ããã ãã€ãããã¯ã¹ã³ãŒããå©çšããã°ãåŒã³åºãå
ã§å€æ°ãäžæçã«æçžããã ãã§ãäžéå±€ã®ã³ãŒããäžå倿Žããããšãªããæ·±ãéå±€ã«ãã颿°ã«æ
å ±ãäŒæãããããšãã§ããŸããã Scheme ã«ããã¬ãã·ã«ã«ã¹ã³ãŒãã®ç¢ºç« ãã®ç¶æ³ã«å€åããããããã®ãã1970幎代ã«ç»å Žãã Scheme ã§ãã Gerald Jay Sussman ãš Guy L. Steele Jr. ã¯ãã©ã ãèšç®ã®çè«ãå¿ å®ã«å®è£
ããéçšã§ã颿°ãå®çŸ©ãããæç¹ã®ç°å¢ãä¿æããã¬ãã·ã«ã«ã¹ã³ãŒããå°å
¥ããŸãããããã«ããã颿°ã®æåãåŒã³åºãå
ã«äŸåãããšããäžç¢ºå®æ§ãæé€ãããæ°åŠçãªäžè²«æ§ãšã¢ãžã¥ãŒã«ãšããŠã®ç¬ç«æ§ã確ä¿ãããŸããã ãã以éãããã°ã©ãã³ã°èšèªã®ã¡ã€ã³ã¹ããªãŒã ã¯ã¬ãã·ã«ã«ã¹ã³ãŒããžãšåæããŠããããã€ãããã¯ã¹ã³ãŒãã¯æ±ãã®é£ãããã€ãŠã®ä»çµã¿ãšããŠãå€ãã®èšèªããå§¿ãæ¶ããŠããããšã«ãªããŸãã Emacs Lisp ã«ãããæå³çãªéžæ Scheme ãã¬ãã·ã«ã«ã¹ã³ãŒãã«ãã£ãŠæ°åŠçã«æŽåããã¢ãã«ã確ç«ããŠãã£ãäžæ¹ã§ãEmacs Lisp ã¯é·ãããã€ãããã¯ã¹ã³ãŒããããã©ã«ããšããŠæ¡çšãç¶ããŸãã 4 ã åœæã®èšç®è³æºã®å¶çŽãšãã£ãå®è£
äžã®çç±ããã£ãããã§ãããçµæãšããŠãã®éžæã¯ãå®è¡æã«æ¯ãèããæ¡åŒµã»äžæžãå¯èœãªãšãã£ã¿ããšããããç°å¢ã§ãã£ã Emacs ã®ç®æããšãããšåã¿åã£ãŠããããã«æããŸãã ãšãã£ã¿ã®æ¡åŒµã«ãããŠã¯ãæ¢åã®ã³ãã³ãããã®å
éšå®è£
ã«æãå
¥ããããšãªããããåŠçã®æèã ããå°ã倿ŽãããããšããèŠæ±ãé »ç¹ã«çŸããŸããEmacs Lisp ã§ã¯ãããããèŠæ±ããã€ãããã¯ã¹ã³ãŒãã«ãã£ãŠèªç¶ã«æºããããšãã§ããŸããã ããç¥ãããŠããäŸããæ€çŽ¢æã®å€§æåã»å°æåã®åºå¥ãå¶åŸ¡ãã case-fold-search ãšãã倿°ã§ãããã®å€æ°ã let ã«ãã£ãŠäžæçã«æçžããã ãã§ããã®å
éšã§åŒã°ããæšæºã®æ€çŽ¢ã³ãã³ãçŸ€ã®æåããŸãšããŠå€æŽã§ããŸãã ( defun my-case-sensitive-search ( keyword ) ( let (( case-fold-search nil )) ( search-forward keyword ))) æèäŒæïŒContext PropagationïŒ ããã°ã©ãã³ã°èšèªå
šäœã«ç«ã¡è¿ãã°ãåè¿°ã®éãäž»æµãšãªã£ãã®ã¯ã¬ãã·ã«ã«ã¹ã³ãŒãã§ããã颿°ã®æ¯ãèããåŒã³åºãå
ã®ç¶æ
ã«äŸåããæ§è³ªã¯ãå€§èŠæš¡åã»è€éåãããœãããŠã§ã¢éçºã«ãããŠãæ±ããé£ããã£ãããã§ãã ã¬ãã·ã«ã«ã¹ã³ãŒããã³ãŒãã®äºæž¬å¯èœæ§ããããããäžæ¹ã§ãã¢ããªã±ãŒã·ã§ã³éçºã«ã¯å¥ã®èª²é¡ãæ®ãããŸãããæèã®äŒæïŒContext PropagationïŒã§ãã Webã¢ããªã±ãŒã·ã§ã³ãäŸã«ãšãã°ãèªèšŒæ
å ±ããã¬ãŒã·ã³ã°IDãªã©ã®æ
å ±ã¯ãåŠçã®éå§ããçµäºãŸã§ãããããéå±€ã®é¢æ°ã§åç
§ããããªã暪æçãªé¢å¿äº 5 ã§ããã¬ãã·ã«ã«ã¹ã³ãŒãã§ãã€ãŒãã«å®è£
ãããšããã¹ãŠã®é¢æ°ã«ãã±ããªã¬ãŒã§æž¡ããªããã°ãªãããäžéå±€ã¯äžèŠãªè²¬åãè² ãããšã«ãªããŸãã ãã®æç€ºçãªèšè¿°ã®ç
©éããé¿ãããããèšèªä»æ§ã®å€åŽã§ãã€ãããã¯ã¹ã³ãŒãçãªæåãå®çŸããä»çµã¿ãå®çšåãããŠããŸãããJava ã«ããã ThreadLocal ããã®ä»£è¡šäŸã§ããèšèªã¬ãã«ã§ã¯éçãªã¹ã³ãŒãã«ããå®å
šæ§ãéžã³ã€ã€ããã©ã³ã¿ã€ã ã§æé»çã«æèãåŒãç¶ãæ©æ§ãåæããçšæãããŠããŸããã ãããããã°ãããçŸä»£ã®ããã°ã©ãã³ã°èšèªã§æèäŒæãã©ãå®çŸãããŠããããèŠãŠãããããšæããŸãã åç¯ã®çްéšã远ããªããŠããæç€ºçã«æž¡ãã¢ãããŒããšæé»çã«äŒæãããã¢ãããŒããããããååšããããšããé°å²æ°ã ãæŽãã§ããããã°ååã§ãã Go ã® context ããã±ãŒãž ãŸãã¯æç€ºçã«æèãæž¡ãäŸãšã㊠Go ãèŠãŠã¿ãŸããGo ã§ã¯ context.Context ã颿°ã®ç¬¬äžåŒæ°ãšããŠæž¡ãèŠçŽã確ç«ãããŠããããã£ã³ã»ã«åŠçãã¿ã€ã ã¢ãŠãããªã¯ãšã¹ãã¹ã³ãŒãã®å€ãäŒæãããŸãã func HandleRequest(w http.ResponseWriter, r *http.Request) { ctx := r.Context() traceId := generateTraceID() ctx = context.WithValue(ctx, traceIdKey, traceId) result, err := processOrder(ctx, orderId) // ... } func processOrder(ctx context.Context, orderId string ) (*Order, error ) { // äžéå±€ã ctx ãåãåããäžäœã«æž¡ã return repository.FindOrder(ctx, orderId) } func (r *Repository) FindOrder(ctx context.Context, orderId string ) (*Order, error ) { traceId := ctx.Value(traceIdKey).( string ) r.logger.Info( "finding order" , "traceId" , traceId, "orderId" , orderId) // ... } æèãåŒæ°ãšããŠæç€ºãããããã颿°ã·ã°ããã£ãèŠãã°ãã®é¢æ°ãæèãå¿
èŠãšããããšãåãããŸãã ãããã context.WithValue ã§æž¡ãããå€ã«ã€ããŠã¯äºæ
ãç°ãªããŸãã ctx ã«äœãå
¥ã£ãŠãããã¯ã·ã°ããã£ããã¯åããããå®è¡æã« ctx.Value(key) ã§åãåºããŸã§äžæã§ããã€ãŸãã context.Context ãšããåŒæ°ã¯æç€ºçã«æž¡ãããŠããŸããããã®äžèº«ãžã®ã¢ã¯ã»ã¹ã¯ããŒã«ããåçãªåç
§ã«ãªã£ãŠããŸãã ã§ã¯ãåã«ãã£ãŠãã®æé»æ§ãè§£æ¶ããæ¹æ³ã¯ããã®ã§ããããã Reader Monad 颿°åããã°ã©ãã³ã°ã®äžçã§ã¯ããã®èª²é¡ã«å¯Ÿããææ³ãšã㊠Reader Monad ãç¥ãããŠããŸãã Reader Monad ã®æ¬è³ªã¯åçŽã§ããç°å¢ R ãåãåã£ãŠå€ A ãè¿ã颿° R => A ããåæå¯èœãªåœ¢ã§æ±ããããã«ãããã®ã§ããScala ã§æžããŠã¿ãŸãããã case class Reader[R, A](run: R => A) { def map[B](f: A => B): Reader[R, B] = Reader(r => f(run(r))) def flatMap[B](f: A => Reader[R, B]): Reader[R, B] = Reader(r => f(run(r)).run(r)) } ããã§ç°å¢ã«äŸåããèšç®ãåæå¯èœãªåœ¢ã§è¡šçŸã§ããŸããããã»ã©ã®äŸã Reader Monad ã§å®è£
ããŸãã case class RequestContext(traceId: String ) def findOrder(orderId: String ): Reader[RequestContext, Order] = Reader { ctx => logger.info(s "finding order: traceId=${ctx.traceId}, orderId=$orderId" ) repository.find(orderId) } def processOrder(orderId: String ): Reader[RequestContext, Result] = for { order <- findOrder(orderId) result <- validateAndProcess(order) } yield result def handleRequest(orderId: String ): Reader[RequestContext, Response] = for { result <- processOrder(orderId) } yield Response(result) // å®è¡æã«ç°å¢ã泚å
¥ val ctx = RequestContext(traceId = "abc-123" ) val response = handleRequest( "order-789" ).run(ctx) 颿°ã®ã·ã°ããã£ã«æ³šç®ããŠãã ããã Reader[RequestContext, Order] ãšããæ»ãå€ã®åãèŠãã ãã§ããã®é¢æ°ã RequestContext ãå¿
èŠãšããããšãåãããŸããå¿
èŠãªæèãåã¬ãã«ã§æç€ºãããŠããŸãã ãŸããfor å
å
衚èšã«ãããç°å¢ã®åãæž¡ããçç¥ã§ããŸãã processOrder 㯠findOrder ãåŒã³åºããŠããŸããã ctx ãæž¡ãã³ãŒãã¯ã©ãã«ããããŸãããReader ã® flatMap ãç°å¢ãäŒæããŠãããããã§ãã ãã®ææ³ã«ãããæèã®æç€ºæ§ãšèšè¿°ã®ç°¡æœããäž¡ç«ã§ããŸãã Scala ã® context parameter ãã®ãããªæžãæ¹ã¯ãã䜿ããããããScala ã§ã¯æ§è³ªã®è¿ãæ©èœãèšèªã¬ãã«ã§ãµããŒããããŠããŸãã case class RequestContext(traceId: String ) def findOrder(orderId: String )(using ctx: RequestContext): Order = { logger.info(s "finding order: traceId=${ctx.traceId}, orderId=$orderId" ) repository.find(orderId) } def processOrder(orderId: String )(using ctx: RequestContext): Result = { val order = findOrder(orderId) // ctx ã¯æé»çã«æž¡ããã validateAndProcess(order) } def handleRequest(orderId: String )(using ctx: RequestContext): Response = { val result = processOrder(orderId) // ctx ã¯æé»çã«æž¡ããã Response(result) } // åŒã³åºãåŽã§ given ãå®çŸ© given ctx: RequestContext = RequestContext(traceId = "abc-123" ) val response = handleRequest( "order-789" ) // ctx ã¯æé»çã«è§£æ±ºããã using ããŒã¯ãŒãã«ãããã³ã³ãã€ã©ãã¹ã³ãŒãå
ããé©åãªå€ãæ¢ããŠèªåçã«åŒæ°ãè£å®ããŸããäžéå±€ã§ã®æç€ºçãªåãæž¡ããäžèŠã§ãããªãããã·ã°ããã£ã«ã¯æèãæç€ºãããŠããŸãã ããã¯ãã¬ãã·ã«ã«ã¹ã³ãŒãã®åå®å
šæ§ãç¶æãã€ã€ããã€ãããã¯ã¹ã³ãŒãã解決ããŠãããã±ããªã¬ãŒåé¡ã«å¯ŸåŠããèšèªã¬ãã«ã®è§£çãšèšããŸãã ãã ããäžéå±€ã®é¢æ°ã (using ctx: RequestContext) ãã·ã°ããã£ã«æã€å¿
èŠããããæèã®ååšèªäœã¯äŒæçµè·¯äžã®ãã¹ãŠã®é¢æ°ã«çŸããŸãã ThreadLocal / AsyncLocalStorage ãããŸã§èŠãŠããã®ã¯ãããããæèãæç€ºçã«è¡šçŸããææ³ã§ãããæ¬¡ã«ãæé»çã«æèãäŒæãããä»çµã¿ãèŠãŠãããŸãã Java ã® ThreadLocal 㯠JDK 1.2ïŒ1998幎ïŒã§å°å
¥ãããŸãããThreadLocal ã¯ãã¹ã¬ããããšã«ç¬ç«ããå€ãä¿æããä»çµã¿ã§ãã Webã¢ããªã±ãŒã·ã§ã³ã§ã¯ã1ã€ã®ãªã¯ãšã¹ãã1ã€ã®ã¹ã¬ããã§åŠçãããå®è¡ã¢ãã«ãäžè¬çã§ããããã®ã¢ãã«ã«ãããŠããªã¯ãšã¹ãã¹ã³ãŒãã®æ
å ±ïŒèªèšŒæ
å ±ããã©ã³ã¶ã¯ã·ã§ã³ãªã©ïŒããåŒæ°ã§æž¡ãããšãªãåŠçã®æµãå
šäœã§å
±æããçšéã§ ThreadLocal ã¯åºã䜿ãããŠããŸããã å
ã»ã©ãšåãäŸã Java ã§æžããŠã¿ãŸãããã public class RequestContext { private static final ThreadLocal<RequestContext> current = new ThreadLocal<>(); public final String traceId; public RequestContext(String traceId) { this .traceId = traceId; } public static RequestContext current() { return current.get(); } public static <T> T runWith(RequestContext ctx, Supplier<T> block) { RequestContext previous = current.get(); current.set(ctx); try { return block.get(); } finally { current.set(previous); } } } public Order findOrder(String orderId) { var ctx = RequestContext.current(); logger.info( "finding order: traceId=" + ctx.traceId + ", orderId=" + orderId); return repository.find(orderId); } public Result processOrder(String orderId) { var order = findOrder(orderId); return validateAndProcess(order); } public Response handleRequest(String orderId) { var result = processOrder(orderId); return new Response(result); } // ãšã³ããªãŒãã€ã³ã var ctx = new RequestContext( "abc-123" ); var response = RequestContext.runWith(ctx, () -> handleRequest( "order-789" )); findOrder ã processOrder ãåŒæ°ã«æèãæã£ãŠããŸããã RequestContext.current() ãåŒã³åºãã ãã§ãåŒã³åºãå
ã§èšå®ãããå€ãååŸã§ããŸãããã㊠runWith ã®ãããã¯ãæããã°ã以åã®å€ã«æ»ããŸããPerl ã® local ãå®çŸããŠããæ¯ãèããšåãã§ããã çŸåšã§ã¯éåæã»äžŠè¡åŠçãäžè¬çã«ãªãããããã«å¯Ÿå¿ãã Java ã® ScopedValueïŒJDK 21ãããã¬ãã¥ãŒïŒããNode.js ã® AsyncLocalStorage ãåæ§ã®æ©èœãæäŸããŠããŸãããããã¯å€ã®ãã¹ããšåŸ©å
ã API ã«çµã¿èŸŒãŸããŠããããã€ãããã¯ã¹ã³ãŒããã³ãŒã«ã¹ã¿ãã¯ãé¡ã£ãŠå€ã解決ããä»çµã¿ã«ããè¿ããã®ã«ãªã£ãŠããŸãã React Context ããã§å°ãèŠç¹ãå€ããŠãããã³ããšã³ãã«ç®ãåããŠã¿ãŸãããã 颿°åŒã³åºãã®é£éãã³ãŒã«ã¹ã¿ãã¯ã圢æããããã«ãReact ã§ã¯ã³ã³ããŒãã³ãã®èŠªåé¢ä¿ãããªãŒæ§é ã圢æããŸãããããŠããã§ããåããã±ããªã¬ãŒåé¡ãçŸããŸãã React ã§ã¯ã芪ããåãžããŒã¿ãæž¡ãéã« props ã䜿ããŸããããããæ·±ããã¹ãããã³ã³ããŒãã³ãã«å€ãå±ããã«ã¯ãéäžã®ãã¹ãŠã®ã³ã³ããŒãã³ãã props ãåãåã£ãŠäžã«æž¡ãå¿
èŠããããŸãããããã props drilling ã§ãã äžéå±€ã®ã³ã³ããŒãã³ããèªèº«ã§ã¯äœ¿ããªã props ã«äŸåããããšã¯ãã³ã³ããŒãã³ãã®åå©çšæ§ãæãªããäžèŠãªåã¬ã³ããªã³ã°ã®åå ã«ããªããŸããReact Context ã䜿ãã°ãContext ã§å²ãã ç¯å²å
ã®ã©ã®æ·±ãã®ã³ã³ããŒãã³ãããã§ããäžéå±€ãçµç±ããã«å€ãååŸã§ããŸãã const ThemeContext = createContext< 'light' | 'dark' >( 'light' ); function App () { const theme = localStorage. getItem ( 'theme' ) ?? 'light' ; return ( < ThemeContext value = { theme } > < Header /> < Main /> < Footer /> </ ThemeContext > ); } function Main () { // Main 㯠theme ãç¥ããªã return < Sidebar /> ; } function Sidebar () { const theme = use(ThemeContext); // äžéå±€ãé£ã³è¶ããŠååŸ return < div className = { theme } > ... </ div > ; } Context ã®ãã¹ãã«ãã£ãŠå€ãäžæžãã§ãããã®ã¹ã³ãŒããæããã°å€åŽã®å€ã«æ»ããã³ã³ããŒãã³ãããªãŒãšãã軞ã¯ç°ãªããŸãããããããã€ãããã¯ã¹ã³ãŒãã®åçºèŠãšèšãããã§ãã 䟵襲ãæãã ãããŸã§èŠãŠããéããæèäŒæã«ã¯äžèœã®è§£æ±ºçããããŸããã æç€ºçã«åŒæ°ã§æž¡ãã°ãäŸåé¢ä¿ã¯æç¢ºã«ãªãã³ãŒãã®è¿œè·¡ã容æã§ããããããäžéå±€ãèªèº«ã§ã¯äœ¿ããªãåŒæ°ãç¥ããªããã°ãªããªããšããåé¡ãæ®ããŸããæé»çãªäŒæã䜿ãã°äžéå±€ã®è² æ
ã¯æ¶ããŸãããä»åºŠã¯äŸåé¢ä¿ãèŠãã«ãããªããŸãã ãã®ãã¬ãŒããªãã«å¯ŸããŠãå¥ã®è»žããèããŠã¿ãããšæããŸããæ¢åã³ãŒããžã®äŸµè¥²ãæããããšããå¶çŽã眮ããå Žåããã€ãããã¯ã¹ã³ãŒãçãªæ¯ãèãã¯ã©ã®ããã«è©äŸ¡ã§ããã§ããããã çŸå®ã®ã³ãŒãããŒã¹ã¯åŸã
ã«ããŠçæ³éãã«ã¯ãªã£ãŠããŸããããã¹ããæèäŒæã®ä»çµã¿ã¯å¿
èŠã ãšããã£ãŠããŠããã¹ã±ãžã¥ãŒã«ãåªå
床ã®éœåã§åŸåãã«ãããŸãŸãã³ãŒããèç©ãããŠããŸãããšã¯èµ·ãããã¡ã§ããããã«æãå
¥ãããšããåŒæ°ã§æç€ºçã«æž¡ããã Reader Monad ãå°å
¥ããã®ãæ£æ»æ³ã§ãããäžéå±€ããã¹ãŠä¿®æ£ããã³ã¹ããèŠåããªãããšããããŸãã 以äžã§ã¯ããã€ãããã¯ã¹ã³ãŒãçãªä»çµã¿ã®å©çšãã劥åã§ã¯ãã£ãŠãæå¹ãªéžæè¢ã«ãªã£ãäŸãå
·äœçã«èŠãŠãããŸããããããåŒã³åºãå
ã®æèã«å¿ããŠå€ãå·®ãæ¿ããããšããèŠæ±ã§ãããããã¯ãŸãã«ãã€ãããã¯ã¹ã³ãŒãã解決ããŠããåé¡ã§ããå®éã«ééããã±ãŒã¹ãç°¡çŽ åããŠç޹ä»ããŸãã ããšãããã¹ãããã« ããšãã°ãå€éš API ãçŽæ¥åŒã³åºããŠãã颿°ãããããã¹ããæžããããšããŸããçæ³çã«ã¯äŸåæ§æ³šå
¥ã§å·®ãæ¿ããããèšèšã«ãªã£ãŠããã¹ãã§ãããçŸå®ã«ã¯ãããªã£ãŠããªãã³ãŒããå€ãã§ãããã ãã®ãšããAPI ã¯ã©ã€ã¢ã³ãã AsyncLocalStorage çµç±ã§åç
§ããããã«å€æŽããã°ããã¹ãæã ããã¹ãããã«ãå·®ã蟌ãããšãã§ããŸããäžéå±€ã®é¢æ°ã·ã°ããã£ã倿Žããå¿
èŠã¯ãããŸããã å
·äœäŸãèŠãŠã¿ãŸãããã // æ¬çªçšã®ååŸé¢æ°ãããã©ã«ãå€ãšããŠèšå® const fetchCategoriesContext = new AsyncLocalStorage< ( ids : CategoryId []) => Promise < Category []> >( { defaultValue : defaultFetchCategories } ) function getFetchCategories () { const fetchCategories = fetchCategoriesContext.getStore() if (!fetchCategories) { throw new Error ( 'unreachable: defaultValue is set' ) } return fetchCategories } ãã® getFetchCategories ãå©çšããŠã«ããŽãªãååŸãã颿°ãå®çŸ©ããŸãã export async function getCategory ( id : CategoryId ): Promise < Category | undefined > { const fetchCategories = getFetchCategories() const categories = await fetchCategories( [ id ] ) return categories[ 0 ] } ãã¹ãæã«ã¯ãã¹ãããã«ãå·®ã蟌ã颿°ãçšæããŸãã /** * ãã¹ãæã« fetchCategories ãå·®ãæ¿ããŠå®è¡ãã */ export async function withTestFetchCategories < T >( fetchCategories : ( ids : CategoryId []) => Promise < Category []> , body : () => T | Promise < T > ): Promise < T > { return fetchCategoriesContext.run(fetchCategories, body) } ãã¹ãã³ãŒãã§ã¯ã withTestFetchCategories ã®ã¹ã³ãŒãå
ã§ãã¹ã察象ãåŒã³åºããŸãã getCategory ãå©çšããŠããã³ãŒãããåãã¹ã³ãŒãå
ã§å®è¡ããã°ãã¹ãããã«ã泚å
¥ãããŸãã test ( 'ã«ããŽãªãååŸã§ãã' , async () => { const stubFetch = async ( ids : CategoryId []) => [ { id : ids[ 0 ], name : 'ãã¹ãã«ããŽãª' } ] await withTestFetchCategories(stubFetch, async () => { const result = await getCategory( 'cat-1' ) expect (result?. name ).toBe( 'ãã¹ãã«ããŽãª' ) } ) } ) ããšãããã£ãã·ã¥ å
ã»ã©ã®ã«ããŽãªããŒã¿ã®äŸã®ç¶ãã§ããã²ãšã€ã®ãªã¯ãšã¹ããåŠçããäžã§ getCategory ãäœåºŠãåŒã°ããŠããããšãããããŸãããæ¯åããã¯ãšã³ãããååŸããã«æžãããã«ãã£ãã·ã¥ãå°å
¥ããŸãããã DataLoader ã䜿ãã°ãã£ãã·ã¥ã§ããŸãããã°ããŒãã«ã«ãã£ãã·ã¥ãããšæŽæ°ã®åæ ãã¡ã¢ãªç®¡çãè€éã«ãªããŸããããã§ãªã¯ãšã¹ãåäœã§ã€ã³ã¹ã¿ã³ã¹ãäœãããšã«ããŸãããå
·äœçã«ã¯ãDataLoader ããªã¯ãšã¹ãã¹ã³ãŒãã§ä¿æããããã« AsyncLocalStorage ãããã²ãšã€è¿œå ããŸãã type CategoryDataLoader = DataLoader < CategoryId , Category | undefined > const categoryDataLoaderContext = new AsyncLocalStorage< CategoryDataLoader >() /** ãªã¯ãšã¹ãåäœã§ DataLoader ãä¿æãã */ export async function withCategoryDataLoader < T >( request : Request , body : () => T | Promise < T > ): Promise < T > { const loader = createCategoryDataLoader(request) return categoryDataLoaderContext.run(loader, body) } function createCategoryDataLoader ( request : Request ): CategoryDataLoader { const fetchCategories = getFetchCategories() return new DataLoader< CategoryId , Category | undefined >( async ( ids ) => fetchCategories(ids, request), { cache : true } ) } getCategory 㯠DataLoader çµç±ã§ååŸããããã«æžãæããŸãã function getCategoryDataLoader (): CategoryDataLoader { const loader = categoryDataLoaderContext.getStore() if (!loader) { throw new Error ( 'No categoryDataLoader in context' ) } return loader } // å©çšåŽã¯ DataLoader ã®ååšãæèããªã export async function getCategory ( id : CategoryId ): Promise < Category | undefined > { return getCategoryDataLoader().load(id) } ãªã¯ãšã¹ããåãããšã³ããªãŒãã€ã³ãã§ withCategoryDataLoader ãé©çšããŸãã export async function loader ( { request } : Route.LoaderArgs ) { return await withCategoryDataLoader(request, async () => { // ãã®äžã§ getCategory ãåŒã³åºãåŠç } ) } ããã§ãäžéå±€ã®é¢æ°ã DataLoader ãåŒãåãå¿
èŠã¯ãªãããªã¯ãšã¹ãåäœã®ãã£ãã·ã¥ãæå¹ã«ãªããŸãã ããšããæèäŒæ å®ã¯äžã®äŸã§ã¯ããã£ãã·ã¥ã ãã§ãªãæèäŒæãå®çŸããŠããŸãã fetchCategories ã®å®è£
ãèŠãŠã¿ãŸãããã async function defaultFetchCategories ( ids : readonly CategoryId [] , request : Request ): Promise <( Category | undefined )[]> { const response = await fetch (BACKEND_API, { method : 'POST' , headers : { 'Content-Type' : 'application/json' , 'X-Forwarded-For' : request. headers . get ( 'X-Forwarded-For' ) ?? '' , 'Cookie' : request. headers . get ( 'Cookie' ) ?? '' , } , body : JSON . stringify ( { ids } ), } ) return response.json() } withCategoryDataLoader ã«æž¡ããã request ã DataLoader ã®çææã«ãã£ããã£ãããããã¯ãšã³ããžã®ãªã¯ãšã¹ãæã« cookie ã X-Forwarded-For ããããåŒãç¶ãã§ããŸãã getCategory ãåŒã³åºãåŽã¯ããã®äŒæã®ä»çµã¿ãæèããå¿
èŠããããŸããã å¿
èŠã«ãªã£ããšãã«ãã³ãŒãã®å€æŽãæå°ã«ä¿ã¡ãªãããæ®µéçã«å°å
¥ã§ããç¹ããã®ã¢ãããŒãã®å©ç¹ã§ãã äžæ¹ã§ããšã³ããªãŒãã€ã³ãã§ withCategoryDataLoader ã®é©çšãå¿ãããšå®è¡æãšã©ãŒã«ãªãããšããèãããããŸããäŸåé¢ä¿ãåã«çŸããªããããã³ã³ãã€ã«æã«ã¯æ€åºã§ããŸãããããã¯ãã€ãããã¯ã¹ã³ãŒãçãªä»çµã¿ã«å
±éãã課é¡ã§ããããã¬ãŒããªããšããŠã®æ
éãªæ€èšãå¿
èŠã§ãã ãããã« React Context ã説æããŠãããšãã«ããã€ãããã¯ã¹ã³ãŒãã®è©±ãããããšããããŸãããããããã®èšäºã®ãã£ããã§ãã æŽå²ããã©ããªããä»ã®æè¡ã®äœçœ®ã¥ããèŠçŽããŠã¿ãã®ãããšãã«ã¯ããããããã®ã§ããæ¬çš¿ãããã®äžç«¯ã§ãæããŠããã ããã°å¹žãã§ãã äžäŒã§ã¯ãæè¡ãæ·±ãçè§£ããªãããããããã·ã¹ãã ããšãã«äœã£ãŠãããšã³ãžãã¢ãåéããŠããŸãã www.ikyu.co.jp ãŸãã¯ã«ãžã¥ã¢ã«é¢è«ãããæ°è»œã«ãå¿åãã ããïŒ job.persona-ats.com ã©ã ãèšç®ã«ãããŠã¯ãã©ã ãæœè±¡ λx. M ã®æ¬äœ M ã«çŸãã倿°ã®ãã¡ãλx ã«ãã£ãŠæçžãããŠãããã®ãæçžå€æ°ããã以å€ãèªç±å€æ°ãšåŒã³ãŸãã ↩ å€ã Lisp ã®äŸãèããŠããã®ã§ãã Perl ã§ã local ã§æžããããšãååãæããŠãããŸããã ↩ John McCarthy, History of Lisp (1978). "In modern terminology, lexical scoping was wanted, and dynamic scoping was obtained. I must confess that I regarded this difficulty as just a bug and expressed confidence that Steve Russell would soon fix it." ↩ çŸåšã® Emacs Lisp ã§ã¯ã¬ãã·ã«ã«ã¹ã³ãŒããéžæããããšãå¯èœã§ãã ↩ 暪æçé¢å¿äºïŒcross-cutting concernïŒãšããã°2000å¹Žä»£ã«æ³šç®ããã AOPïŒAspect Oriented Programming, ã¢ã¹ãã¯ãæåããã°ã©ãã³ã°ïŒã§ããããã®äž»èŠãªãŠãŒã¹ã±ãŒã¹ã®ã²ãšã€ã«æèäŒæã®èªååããããŸããããã°åºåããã©ã³ã¶ã¯ã·ã§ã³ã®ã³ã³ããã¹ããªã©ã¯ãThreadLocal çã®æäœãè£åŽã§é èœããå
žåçãªäŸã§ããã ↩
åç»
該åœããã³ã³ãã³ããèŠã€ãããŸããã§ãã










