Upgrade to Pro — share decks privately, control downloads, hide ads and more …

はてなリモートインターンシップ2023 Perlブートキャンプ講義資料

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Hatena Hatena
October 18, 2023

はてなリモートインターンシップ2023 Perlブートキャンプ講義資料

Avatar for Hatena

Hatena

October 18, 2023
Tweet

More Decks by Hatena

Other Decks in Programming

Transcript

  1. Perl? • Go と違って、コンパイルをしないインタプリタ型⾔語 • Better shell としても使えるし、ウェブアプリケーションを書くこ とだってできる •

    素早いウェブ開発の道具として、古くから⼈気の Lightweight Language • はてな/DeNA/mixi/LINE... • みなさんが配属される予定のチームでも #hatenaintern)*)+
  2. Perl? • Perl == Perl( • 偶数が安定版、奇数が開発版 • Perl3がリリースされた時期もあった •

    今はRakuという別⾔語になっている • Perl(とPerl3(Raku)はJavaと JavaScriptくらいの差がある #hatenaintern)*)+
  3. ドキュメントはperldocで引く % perldoc Carton # Ϟδϡʔϧʢޙड़ʣͷυΩϡϝϯτ % perldoc -f print

    # ૊ΈࠐΈؔ਺͸ -f % perldoc -v @_ # ૊ΈࠐΈม਺͸ -v % perldoc perl #hatenaintern)*)+
  4. CPAN • The Comprehensive Perl Archive Network • https://metacpan.org •

    世界中のさまざまなPerlモジュールが集まっている • Perlの⾔語的な強みの⼀つ=コミュニティ #hatenaintern)*)+
  5. Carton • Ruby でいう Bundler みたいなもの • cpanfile に書いた モジュール名@バージョン

    を、ローカルのデ ィレクトリ local/ にインストールしてくれる • チームでは Docker 使うのであまり問題にはならないかも • 現代ではCartonの後継としてCarmelも開発されている #hatenaintern)*)+
  6. • モジュール • 拡張⼦は.pm package Example::Greeter; use strict; use warnings;

    sub greet { my ($class, $what) = @_; print "hello, $what\n"; } 1; #hatenaintern)*)+
  7. • メインスクリプト • 拡張⼦は.pl • Prologも同じ拡張⼦ use strict; use warnings;

    use lib 'lib'; use Example::Greeter; Example::Greeter->greet('world'); • 実⾏ % perl -Ilib main.pl hello, world #hatenaintern)*)+
  8. おまじない • use strict; use warnings; • 素のPerlはかなり⾃由 • もともとawk/sedの影響が強いので同じようなことができる

    • use strict; すると my で宣⾔していない変数があると静的にエラー • use warnings; すると警告が有効になる • 詳しくは perldoc strict / perldoc warnings #hatenaintern)*)+
  9. $: スカラ • 1つの値 • 数字も⽂字列もすべてスカラ my $scalar1 = 'test';

    my $scalar2 = 1000; my $scalar3 = \@array; # ϦϑΝϨϯεʢޙड़ʣ • 0や""(空⽂字列)は falsy な値として扱われる • "0" もfalsy #hatenaintern)*)+
  10. undef • スカラ変数の初期値 • いわゆる undefined とか nil とか •

    defined 組み込み関数で undef かどうかチェックできる my $x; print $x; # "Use of uninitialized value $x in print" #hatenaintern)*)+
  11. 配列の操作 $array[0]; # get $array[1] = 'hoge'; # set push

    @array, 'meow'; # ࠷ޙʹཁૉΛ௥Ճ my $v = shift @array; # ࠷ॳͷཁૉΛऔΓআ͍ͯฦ͢ my $length = scalar @array; # ௕͞ for my $e (@array) { # શཁૉϧʔϓ print $e; } #hatenaintern)*)+
  12. 配列の操作 my @doubles = map { $_ * 2 }

    @numbers; # ͢΂ͯΛ2ഒʹͨ͠഑ྻΛ࡞Δ my @over20 = grep { $_ > 20 } @numbers; # 20ΑΓେ͖ͳ਺͚ͩΛूΊͨ഑ྻΛ࡞Δ • $_ は特殊変数 • この場合では配列の各要素が順に取り出されて⼊ってくる #hatenaintern)*)+
  13. %: ハッシュ • いわゆるディクショナリやマップ my %hash = ( perl =>

    'larry', ruby => 'matz', ); • => は"fat comma"と呼ばれ、( perl => 'larry' ) は ( 'perl', 'larry' ) と同⼀ #hatenaintern)*)+
  14. Perlのデータ構造 • Perlのデータ構造を意味上で分類するとスカラとリストの2種類 • スカラ(単⼀)の値 • ⽂字列(hoge) • 数値 •

    リファレンス(後述) • リスト • (1,2,3,'hoge', 'foo') • リストをどう使うかはシジル(@, %)で決定する #hatenaintern)*)+
  15. リストのつかいかた • リストをどう使うかはシジル(@, %)で決定する • @array = (1,2,3) • こうすると配列

    • %array = (1,2,3) • こうするとハッシュ • 1 => 2, 3 => undef #hatenaintern)*)+
  16. リファレンス • ⼊れ⼦の⾏列を作ってみるか... my @matrix = ( (0, 1, 2,

    3), (4, 5, 6, 7), ); • このコードは配列の合成になる • リストを⼊れ⼦にできない my @matrix = (0, 1, 2, 3, 4, 5, 6, 7); #hatenaintern)*)+
  17. そこでリファレンス my @array = ('a', 'b', 'c'); my $ref =

    \@array; # @array ΁ͷϦϑΝϨϯε my $ref = ['a', 'b', 'c']; # ্هͷུهɻͪͳΈʹ \('a', 'b', 'c') ͸ผ෺ # 2ͭͷ഑ྻ΁ͷϦϑΝϨϯεΛ΋ͬͨʢ௕͞2ͷʣ഑ྻ my @matrix = ( [0, 1, 2, 3], [4, 5, 6, 7], ); #hatenaintern)*)+
  18. ハッシュリファレンス my %hash = ( perl => 'larry', ruby =>

    'matz', ); my $ref = \%hash; # ུه my $ref = { perl => 'larry', ruby => 'matz', }; #hatenaintern)*)+
  19. ハッシュリファレンスへのアクセス my $ref = { perl => 'larry', ruby =>

    'matz', }; # % Λ಄ʹ͚ͭͯσϦϑΝϨϯε # keys͸૊ΈࠐΈؔ਺ɻϋογϡͷΩʔͷҰཡΛऔಘ͢Δ my @keys = keys %$ref; print $ref->{perl}; # -> Ͱ௚઀ΞΫηε #hatenaintern)*)+
  20. デリファレンスいろいろ • なにかの式をデリファレンスするときは @{ ... } とか %{ ... }

    で 囲む my $a_of_a = [ [1, 2, 3], [4, 5, 6], ]; my @array = @{ $a->[1] }; #hatenaintern)*)+
  21. 正規表現 • Perlの強みのひとつ。めちゃ強⼒ • /.../ で正規表現リテラルを⽣成、=~ で⽂字列にマッチさせる my ($id) =

    ("͜Μʹͪ͸ɺid:motemen Ͱ͢" =~ /id:(.+)/); # จࣈྻϚονͰҰ෦Λൈ͖ग़͢ my @lines = split /\n/, $text; # ೖྗΛߦʹ෼ׂ • perldoc perlre #hatenaintern)*)+
  22. そのほか • if ⽂とかは想像通りのものがだいたいある • else if はなくて elsif •

    ループの制御構⽂ • continueは next, breakは last • ⽂字列の⽐較は == などではなく eq • 数値の場合は==なので気をつけよう • perldoc perlop #hatenaintern)*)+
  23. そのほか • ⽂字列の結合は .(ドット)等 $hoge = 'abc' . 'def' #

    abcdef • qw(foo bar baz) は ('foo', 'bar', 'baz') の糖⾐構⽂ • perldoc -f qw #hatenaintern)*)+
  24. そのほか • リストの全体を加⼯するときはmapなどを使う • 全体を[]でくくると配列 • 全体を{}でくくるとハッシュ my $double_array =

    [ map { $_ * 2} (1,2,3) ]; # [2, 4, 6] my $hash = { map { $_ => 1} (qw(foo bar baz)) }; # { foo => 1, bar => 1, baz => 1} #hatenaintern)*)+
  25. コンテキスト • Perlの難しいところのひとつ • 式を評価する際に考慮する必要がある • スカラコンテキストとリストコンテキストがある my @array =

    (10, 20, 30); my @x = @array; # ͜ͷ @array ͸ϦετίϯςΩετͰධՁ͞ΕΔ my $y = @array; # ͜ͷ @array ͸εΧϥίϯςΩετͰධՁ͞ΕΔ my ($z) = @array; # ͜ͷ @array ͸ϦετίϯςΩετͰධՁ͞ΕΔ #hatenaintern)*)+
  26. コンテキスト • @x が (10, 20, 30) になるのはまあ⾃然 • では

    $y は...? • $y == 3 • 配列をスカラコンテキストで評価するとその⻑さを返す • $zには配列の先頭要素が代⼊され($z == 10)配列の残りは 捨てられる #hatenaintern)*)+
  27. コンテキストのよくある罠 my $in = { name => ('foo', 'bar', 'baz')

    }; my $in = { name => 'foo', bar => 'baz', }; という感じになり、なぜかbarという不思議なキーが⽣え、不可解 なバグの原因となりうる #hatenaintern)*)+
  28. コンテキストクイズ sort <͜͜>; length <͜͜>; if (<͜͜>) { } for

    my $i (<͜͜>) { } $obj->method(<͜͜>); my $x = <͜͜>; my ($x) = <͜͜>; my @y = <͜͜>; my %hash = ( key0 => 'hoge', key1 => <͜͜>, ); scalar(<͜͜>); <͜͜>; #hatenaintern)*)+
  29. コンテキストクイズ(解答) sort <Ϧετ>; length <Ϧετ>; if (<εΧϥ>) { } for

    my $i (<Ϧετ>) { } $obj->method(<Ϧετ>); my $x = <εΧϥ> my ($x) = <Ϧετ>; my @y = <Ϧετ>; my %hash = ( key0 => 'hoge', key1 => <εΧϥ>, ); scalar(<Ϧετ>); <εΧϥ>; #hatenaintern)*)+
  30. 関数(サブルーチン) sub foo { my ($a, $b, $c) = @_;

    } のように宣⾔して foo(1, 2, 3); で呼び出す。引数なしの関数呼び出しはカッコ省略できる #hatenaintern)*)+
  31. 引数の受け取り⽅ sub add { my ($x, $y) = @_; return

    $x + $y; } my $three = add(1, 2); • add(1,2) と呼び出したときの引数は @_ という特殊な配列に格納さ れる • これが($x, $y)に分割代⼊される #hatenaintern)*)+
  32. 引数の受け取り⽅ • shiftを使う • 引数なしのshiftは暗黙的に@_を引数に取る • my $arg1 = shift;とすると@_の先頭要素が$arg1に代⼊され

    る • @_は配列なので... • my $arg1 = $_[0]で最初の引数にアクセスすることもできる #hatenaintern)*)+
  33. 引数処理イディオム sub func1 { my ($arg1, $arg2, %args) = @_;

    my $opt1 = $args{opt1}; my $opt2 = $args{opt2}; } func1('hoge', 'fuga', opt1 => 1, opt2 => 2); 最後に%argsと受けることで(省略可能な)名前付き引数を実現で きる #hatenaintern)*)+
  34. モジュールシステム • パッケージ package A; sub foo { ... }

    package B; sub bar { ... } それぞれ A::foo() / B::bar() で関数を参照できる #hatenaintern)*)+
  35. 典型的なモジュール package Foo::Bar::Baz; use strict; use warnings; # ͜ͷύοέʔδͷ֎͔Β͸ Foo::Bar::Baz::public_function

    ͰΞΫηεͰ͖Δͧ sub public_function { ... } # ඇެ։ͳؾ෼ͷϝιου͸ _ Ͱ͸͡ΊΔͧɻؾ෼͚ͩͳͷͰ֎͔ΒΞΫηε΋Ͱ͖ͪΌ͏͕ɻ sub _private_function { ... } # Ϟδϡʔϧͷ࠷ޙʹ͸͔ͳΒͣਅ஋Λه͢ɻͦ͏͠ͳ͍ͱ use ͕ࣦഊ͢Δͧɻ 1; #hatenaintern)*)+
  36. 解説 • use MODULE 'foo', 'bar'...; でモジュールに⽣えている関数をイ ンポートできる • 本当はもう少し汎⽤的で複雑だが、この理解で困らない

    • useの引数なしでも勝⼿にインポートしてくれるモジュールも ある • Data::Dumper / JSON など #hatenaintern)*)+
  37. bless • blessがオブジェクト指向Perlにおける最後の登場⼈物 # ͳΜ͔σʔλ͕͋Δʢී௨͸ϋογϡϦϑΝϨϯεʣ my $data = { name

    => 'motemen' }; # σʔλʹύοέʔδΛඥ෇͚Δͱ my $self = bless $data, 'Hatena::Engineer'; # ϝιου͕ݺ΂Δʂ ͜͜Ͱ͸ Hatena::Engineer::tweet $self->tweet(); #hatenaintern)*)+
  38. ͍͍͔ɺΈΜͳ ɹɹɹɹɹɹɹɹ ƅшƅ ) ɹɹɹɹɹɹɹɹ(|ɹy |) ϋογϡϦϑΝϨϯεͱ package Ͱ͸खଓ͖ܕϓϩάϥϛϯά͔͠Ͱ͖ͳ͍͕ ɹɹɹɹɹ

    {}ɹ (ƅшƅ)ɹpackage ɹɹɹɹɹɹɹʘʗ|ɹy |ʘʗ ɹɹɹɹೋͭ߹Θ͞Ε͹OOPͱͳΔ ɹɹɹɹɹɹɹɹ(ƅшƅ)ɹ bless ɹɹɹɹɹɹɹɹ(ʘʗʘʗ #hatenaintern)*)+
  39. コンストラクタ package Person; use strict; use warnings; sub new {

    my ($class, %args) = @_; return bless \%args, $class; } #hatenaintern)*)+
  40. 使い⽅ my $person = Person->new(age => 18); # { age

    => 18 } ͕ Person ʹ bless ͞Εͨ΋ͷ #hatenaintern)*)+
  41. 使い⽅ • Person->new(age => 01) は Person::new('Person', age => 01)

    の 糖⾐構⽂ • こうやってクラスメソッドを定義する • blessされていてもハッシュリファレンスであることに変わりはない • $person->{age} で中⾝にアクセスすることも可能 • できるけどオブジェクトを使うところではやらない #hatenaintern)*)+
  42. メソッド package Person; use strict; use warnings; sub new {

    my ($class, %args) = @_; return bless \%args, $class; } sub age { my ($self) = @_; return $self->{age}; } sub incr_age { my ($self) = @_; $self->{age}++; } #hatenaintern)*)+
  43. メソッド $person->incr_age; • $person->incrage_ は $person のbless先である Person をた どって、結局

    Person::incr_age($person) と同様 • こうやってインスタンスメソッドが定義できる #hatenaintern)*)+
  44. 継承 package Animal; use strict; use warnings; sub new {

    ... } sub walk { ... } 1; package Dog; use strict; use warnings; use parent 'Animal'; 1; #hatenaintern)*)+
  45. 継承 my $dog = Dog->new(); $dog->walk(); # Animal::walk ͕ݺ͹ΕΔ •

    仕組みとしては可能だけどあまり最近は使われていない • Perl⾃体がIDEのサポートを受けづらい(無いわけではない) • 複雑になる #hatenaintern)*)+
  46. 便利なCPANモジュール package Foo; use strict; use warnings; use Class::Accessor::Lite (

    new => 1, ro => ['bar'], ); 1; my $foo = Foo->new(bar => 1); # new Ͱ͖ͯΔ $fop->bar; # bar ϝιου΋ੜ͑ͯΔ #hatenaintern)*)+
  47. おまけ (現代のPerl) use v5.38; use feature 'class'; no warnings 'experimental::class';

    class My::Example { field $x; ADJUST { $x = "Hello, world"; } method print_message { say $x; } } My::Example->new->print_message; #hatenaintern)*)+
  48. テスト Testなんとかみたいなモジュールを使ってテストする。 社内(外)でよく使われているテストモジュール • Test&::V) • モダンなテストモジュール • Test::More •

    昔からよく使われているテストモジュール • Test::Class • ユニットテストを書きやすくするモジュール #hatenaintern)*)+
  49. テスト use strict; use warnings; use Test::More; use Person; my

    $person = Person->new(age => 18); is $person->age, 18, '࠷ॳ͸18ࡀ'; $person->incr_age; is $person->age, 19, 'incr_age ݺΜͩΒ19ࡀ'; done_testing; #hatenaintern)*)+
  50. テスト % prove -Ilib -v t/Person.t t/Person.t .. ok 1

    - ࠷ॳ͸18ࡀ ok 2 - incr_age ݺΜͩΒ19ࡀ 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.04 cusr 0.00 csys = 0.06 CPU) Result: PASS #hatenaintern)*)+
  51. Test::Class package t::Person; use strict; use warnings; use parent 'Test::Class';

    sub setup : Test(setup) { # ͳʹ͔ෆࢥٞͳຐ๏Ͱؔ਺໊ͷ͋ͱʹΞϊʔςʔγϣϯͰ͖Δ # ֤ςετલͷηοτΞοϓʢม਺ΛΫϦΞͨ͠Γͱ͔ʣ } sub incr_age : Tests { is ...; } #hatenaintern)*)+