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

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

Hatena
October 18, 2023

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

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)*)+