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

Perlブートキャンプ

Avatar for Hatena Hatena
November 14, 2025

 Perlブートキャンプ

2025-11-14 YAPC::Fukuoka 2025

Avatar for Hatena

Hatena

November 14, 2025
Tweet

More Decks by Hatena

Other Decks in Technology

Transcript

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

    素早いウェブ開発の道具として、古くから人 気のLightweight Language ◦ はてな/DeNA/Mobile Factory/mixi/LINE... 7
  2. Perl? • Perl == Perl5 ◦ 偶数が安定版、奇数が開発版 • Perl6がリリースされた時期もあった ◦

    今はRakuという別言語になっている ◦ Perl5とPerl6(Raku)はJavaとJavaScriptくらいの差 がある 8
  3. Perlコードはこんな見た目 package Example::Greeter; use v5.42; sub greet { my ($class,

    $what) = @_; say "Hello, $what!"; } 13 • モジュール ◦ 拡張子は.pm
  4. Perlコードはこんな見た目 14 • メインスクリプト ◦ 拡張子は.pl • 実行 $ perl

    hello.pl Hello, World! use v5.42; use lib 'lib'; use Example::Greeter; Example::Greeter->greet('World');
  5. ドキュメントはperldocで引く $ perldoc Carmel # モジュール (後述)のドキュメント $ perldoc -f

    print # 組み込み関数は -f $ perldoc -v @_ # 組み込み変数は -v $ perldoc perl 16
  6. CPAN • The Comprehensive Perl Archive Network ◦ https://metacpan.org/ •

    世界中のさまざまなPerlモジュールが集まっ ている • Perlの言語的な強みの一つ=コミュニティ 17
  7. Carmel, Carton • Rubyで言うBundler ◦ cpanfile, cpanfile.snapshotで依存を管理して ◦ carmel exec

    ...で実行する • プロジェクトのlocal/に展開して使う ◦ vendor/bundleと思えばOK 18
  8. よりよいデフォルト値 • 古い定型文が減る方向に ◦ use strict; use warnings; ◦ use

    strictはJSにも輸出された プラグマ ▪ 互換性を壊さずに進化するため • 良いfeatureを有効にする ◦ say, module_true, isa, try, ... 26 use v5.42; # 以下の記述と同じ use warnings; use strict; no feature ':all'; use feature ':5.42';
  9. use strict; use warnings; 27 • ファイルの先頭には必ず書きましょう my $message =

    "hello"; print $messsage; # typo! # => エラーにならない! $messagge = "bye"; # typo! # => $messagge がグローバル変数になる!
  10. • Defined ◦ Ref ▪ ArrayRef ▪ HashRef ▪ ScalarRef

    ▪ CodeRef ▪ RegexpRef ▪ GlobRef ▪ FileHandle ▪ Object データ型 > スカラー 33 • Bool • Undef • Defined ◦ Value ▪ Str • Int
  11. データ型 > 配列 • いわゆる配列です ◦ my @array = (1,

    2, 'foo', 'bar'); • 1要素を取り出すときは$でアクセス ◦ my $elem = $array[2]; ◦ 超絶に分かりづらいと思う ▪ $arrayも同時に存在できるので死 ▪ 普段は直接配列を扱わずにArrayRefを使う(後述)ので 今は流してくれ 34
  12. データ型 > 配列 • 複数要素を取り出すときは@ ◦ my @foo = @array[1,2]

    • 分割代入もできます ◦ my ($one, $two, @rest) = (1, 2, 'foo', 'bar'); ◦ my ($foo) = @array; は先頭要素を取り出している 35
  13. データ型 > 配列 36 • 基本操作たち $array[0]; # get $array[1]

    = 'hoge'; # set my $length = scalar @array; # 長さ my $last_idx = $#array; # 最後の添字 my @slice = @array[1..4]; # スライス for my $e (@array) { # 全要素ループ print $e; }
  14. データ型 > 配列 • 最後の添字って何 ◦ こういう使い方でeach_with_index的で便利 37 my @array

    = ('apple', 'banana', 'cherry'); my @result = map { "$_: $array[$_]" } 0..$#array; # => ('0: apple', '1: banana', '2: cherry')
  15. データ型 > ハッシュ • key, valueの組です ◦ my %hash =

    (foo => 1, bar => 2); • 取り出すときは $hash{foo} ◦ =>の左や{}の中はbare wordが許される 38
  16. データ型 > ハッシュ • 配列との相互変換ができる ◦ my @array = %hash;

    ◦ my %hash = @array; • => はfat commaと呼ばれる ◦ my %h = (foo, 1) と my %h = (foo => 1) が同じ ◦ hashにするときは要素が偶数じゃないとwarn 39
  17. データ型 > ハッシュ 41 • 基本操作たち $hash{perl}; # get $hash{perl}

    = 'larry'; # set for my $key (keys %hash) { # 全要素のキー my $value = $hash{$key}; # キーで各要素を get }
  18. データ型 > 真偽値 42 • falseや0、空文字はfalsy ◦ "0" もfalsy •

    空リストもfalsy ◦ スカラーコンテキストで0になる(後述) • 他はtruthy
  19. リファレンス > ArrayRef my @array = ('a', 'b', 'c'); my

    $ref = \@array; # @array へのリファレンス my $ref = ['a', 'b', 'c']; # 上記の略記。 # ちなみに \('a', 'b', 'c') は別物 47
  20. リファレンス > ArrayRef 50 # デリファレンス my @array = @$ref;

    # 頭に @ をつけて配列に戻す # もしくは my $scalar = $ref->[1]; # -> を使って直接要素を取り出す • リファレンスから値を取り出す
  21. my %hash = ( perl => 'larry', ruby => 'matz',

    ); my $ref = \%hash; リファレンス > HashRef 51 # 略記 my $ref = { perl => 'larry', ruby => 'matz', };
  22. リファレンス > HashRef 52 # % を頭につけてデリファレンス # keysは組み込み関数。ハッシュのキーの一覧を取得する my

    @keys = keys %$ref; print $ref->{perl}; # -> で直接アクセス • リファレンスから値を取り出す
  23. デリファレンスいろいろ 53 my $a_of_a = [ [1, 2, 3], [4,

    5, 6],]; my @array = @{ $a_of_a->[1] }; • なにかの式をデリファレンスするときは @{ ... } とか %{ ... } で囲む
  24. デリファレンスいろいろ 54 my $a_of_a = [ [1, 2, 3], [4,

    5, 6]]; my @array = $a_of_a->[1]->@*; # => (4, 5, 6) • Postfix dereference
  25. デリファレンスいろいろ 55 my $list = [1, 2, 3]; push @$list,

    4; • 必要なときだけデリファレンスする
  26. コンテキスト 58 my @array = (10, 20, 30); my @x

    = @array; my $y = @array; my ($z) = @array; • それぞれ何が入っているでしょうか
  27. コンテキスト 59 my @array = (10, 20, 30); my @x

    = @array; # @array はリストコンテキストで評価される my $y = @array; # @array はスカラコンテキストで評価される my ($z) = @array; # @array はリストコンテキストで評価される • それぞれ何が入っているでしょうか
  28. • $yには、配列をスカラコンテキストで評価す るので個数が返る コンテキスト 60 my @array = (10, 20,

    30); my @x = @array; # @x = (10, 20, 30) my $y = @array; # $y = 3 my ($z) = @array; # $z = 10
  29. • $zには、配列の先頭要素が代入され、残りは 捨てられている コンテキスト 61 my @array = (10, 20,

    30); my @x = @array; # @x = (10, 20, 30) my $y = @array; # $y = 3 my ($z) = @array; # $z = 10
  30. 演算子 64 • 普通の演算子はだいたいある ◦ defined-or (//) があるのは便利 • 文字列の比較は

    == ではなく eq ◦ ==は数値比較用なので注意 ◦ 文字列比較にはeq, ne, gt, le等を用いる
  31. 制御構造 66 • for my $e と受けないと$_が使われる ◦ for (@$array)

    { say $_ }; ◦ $_はここでは処理中の要素を表す特殊変数 • forのキーワードは珍しいか? ◦ continueではなくnext, breakではなくlast
  32. Enumerable色々 67 my $items = [(3..7)]; for my $item (@$items)

    { ... } my $res = [ grep { $_ % 2 } @$items ]; # => # [3, 5, 7]
  33. Enumerable色々 68 my $items = [(3..7)]; my $doubled = [

    map { $_ * 2 } @$items ]; #=> [6, 8, 10, 12, 14] use List::Util qw(all); if (all { $_ > 0 } @$items) { say "すべて 0 より大きい" } # List::Util には min, uniq, sample, first 等だいたいある
  34. 例外 71 use Try::Tiny; try { ...; } catch {

    my $err = $_; # $_にエラーメッセージが入っている # die $err; # 再スロー };
  35. サブルーチン 74 # サブルーチン宣言 sub foo { my ($a, $b,

    $c) = @_; } # サブルーチン呼び出し foo(1, 2, 3); # 引数なしで呼び出す場合はカッコを省略できる
  36. サブルーチン > 引数 75 sub add { my ($x, $y)

    = @_; return $x + $y; } my $three = add(1, 2); • 引数1,2は@_という特殊な配列に格納される ◦ これが($x, $y)に分割代入される
  37. サブルーチン > 引数 76 sub add { my $x =

    shift; my $y = $_[0]; # shift したので y が先頭要素 return $x + $y; } • shiftを使う ◦ 引数なしだと暗黙的に@_になり、先頭要素を取り出す • $_[0]で配列の最初を取り出すことも
  38. サブルーチン > 引数 77 sub func1 { my ($arg1, $arg2,

    %args) = @_; my $opt1 = $args{opt1}; my $opt2 = $args{opt2}; } func1('hoge', 'fuga', opt1 => 1, opt2 => 2); • よくやるイディオム ◦ 最後に%argsと受けると省略可能な名前付き引数に
  39. サブルーチン > 引数(現代) 78 sub add($x, $y) { return $x

    + $y; } • Perl界にも仮引数があります! • 私はISUCON以外で見たことない
  40. サブルーチン > はてなでは 79 use Smart::Args::TypeTiny qw(args); sub add {

    args my $x => 'Int', my $y => 'Int'; return $x + $y; } • 実行時型チェックも同時に実現する Smart::Args::TypeTinyを使っている
  41. サブルーチン > 値の返し方 81 sub swap_list($x, $y) { return ($y,

    $x) } my ($x, $y) = swap_list('Hello','World'); #=> ($x: World', $y: 'Hello') • 多値を返して分割代入で受けられる ◦ スカラーで受け取ると個数になるから注意
  42. サブルーチン > 引数 82 • 無名サブルーチンを引数で渡すのもよく見る ◦ 高階関数やブロックと同じ sub with_block

    { say "start"; $_[0]->(); # 渡された無名サブルーチンを実行 say "end"; } with_block(sub { say "in block" });
  43. パッケージ > 名前空間 86 package A; sub foo { ...

    } package B; sub bar { ... } • それぞれA::foo、B::barで呼び出せる
  44. パッケージ > モジュールロードの仕組 み 87 use My::File; # => My/File.pm

    がロードされる • @INC(グローバル変数)に設定されたパスを検索 ◦ 慣習的に ./lib を@INCに含めている
  45. パッケージ > モジュールロードの仕組 み 88 use My::File; # => My/File.pm

    がロードされる • .pm=PerlModule。書き捨て以外は基本.pm • Carmel/Cartonで入れる他、コアモジュール (Perlインストール時に同梱)が数百ある ◦ $ corelist -v v5.34.1 で見てみよう
  46. • オブジェクトとは ◦ プログラムの対象となるモノ ◦ データ + 手続き • クラスで実装されることが多い

    ◦ クラスには自身の持つデータに対する手続き(メソッ ド)が定義されている オブジェクト指向 91
  47. bless 94 # なんかデータがある(普通はハッシュリファレンス) my $data = { name =>

    'motemen' }; # データにパッケージを紐付けると my $self = bless $data, 'Hatena::Engineer'; # メソッドが呼べる! ここでは Hatena::Engineer::tweet $self->tweet();
  48. いいか、みんな         (゚д゚ )         (| y |) ハッシュリファレンスと package では手続き型プログラミングしかできないが       {} 

    ( ゚д゚) package        \/| y |\/     二つ合わさればOOPとなる         ( ゚д゚)  bless         (\/\/ オブジェクト指向 95
  49. • Person->new(age => 18)は Person::new('Person', age => 18) オブジェクト指向 >

    コンストラクタ 97 my $person = Person->new(age => 18); # { age => 18 } が Person に bless されたもの
  50. オブジェクト指向言語として使う 99 my $person = Person->new(name => 'motemen', age =>

    18); # 元々 HashRef を bless しただけなので中身にアクセス可能 $person->{age} = 3; # だけど、当然 $person->age(3) でアクセスする package Person; sub age { $self = shift; $self->{age} = $_[0]; }
  51. package Person; use Class::Accessor::Lite ( new => 1, rw =>

    [ qw(name age) ], ); オブジェクト指向(ライブラリ) 101 • ものすごく書きやすくて便利だったが……
  52. オブジェクト指向(現代) 102 use v5.42; use experimental 'class'; # まだ experimental

    だが class Person { # class 記法が入った! field $name :param :reader; # 属性とアクセサ定義 method hello { say "Hi, I'm $name." } # メソッド定義 } my $onk = Person->new(name => 'onk'); $onk->hello;
  53. { my $x = 10; say $x; # 10 }

    say $x; # エラー(見えない) スコープ • 変数の見える範囲 ◦ myはレキシカルスコープ内に限定する宣言 ◦ スコープを絞るために任意にブロックを作れる 104
  54. 入出力 > 読み込み 107 open my $fh, '<', 'input.txt' or

    die $!; while (my $line = <$fh>) { ...; } close $fh; • 有名なor die ◦ or の優先順位が低いおかげでカッコが要らない ◦ ( open my $fh, '<', $file ) or die $!
  55. open my $fh, '<', 'input.txt' or die $!; local $/

    = undef; # 入力区切り文字を変更 my $content = <$fh>; # ファイル全体を一度に読める close $fh; 入出力 > 読み込み 108 • いわゆるslurpパターン • 行指向言語なことを示していて慣れたら好き
  56. my $content = do { # スコープを抜けたら自動 close open my

    $fh, '<', 'input.txt' or die $!; local $/; # 代入しなくても undef になる <$fh>; }; 入出力 > 読み込み 109 • こういう書き方をしているところも多いかも ◦ do {} はブロックの結果を式として返す
  57. open my $fh, '>', 'output.txt' or die $!; print $fh

    "Hello\n"; close $fh; 入出力 > 書き込み 110 • printの第1引数にファイルハンドルを渡す ◦ デフォルトでSTDOUT ◦ 第1引数なのにカンマがないけどそういうものらしい
  58. 特殊変数 112 • 今まで説明してきたもの ◦ $_ : 色んなところで使う。mapやgrepの処理対象等 ◦ @_

    : 引数 ◦ $@ : evalブロックの例外メッセージ ◦ $! : システムコール失敗時のエラーメッセージ ◦ $/ : 入力の区切り文字
  59. 特殊変数 113 • English module で別名が付いている ◦ $_ : $ARG

    ◦ @_ : @ARG ◦ $@ : $EVAL_ERROR ◦ $! : $ERRNO ◦ $/ : $INPUT_RECORD_SEPARATOR
  60. use utf8; print length 'ほげ'; use utf8; 119 • そこでuse

    utf8; • 実行します $ perl hoge.pl 2 • ええやん!
  61. use utf8; 120 • utf8 プラグマをつけると Perl はコード内の マルチバイト文字を UTF-8

    の文字列として解 釈し、Perl 内部表現の文字列に変換する • UTF-8 で記述された "ほげ" を UTF-8 として 解釈すると length "ほげ" は 2 になる
  62. use utf8; print 'ほげ'; use utf8; 121 • けど…… $

    perl hoge.pl Wide character in say at hoge.pl line 2. ほげ • なんか出た
  63. 正規表現 127 • Perlと言えば正規表現 ◦ 出自からしてテキスト処理に特化 ◦ Practical Extraction and

    Report Language • 正規表現リテラルで、読み下しやすい if ($line =~ /ERROR/) { warn "error detected"; }
  64. 正規表現 128 • m// マッチ演算子 ◦ if ($str =~ m/foo/)

    { ... } # m は省略可 • s/// 置換演算子 ◦ $str =~ s/foo/bar/; ▪ $strを破壊的に変更する ◦ Perl v5.14 で非破壊操作が可能になった ▪ my $new = $str =~ s/foo/bar/r;
  65. 正規表現 129 while (<LOG>) { next unless /^ERROR\b/; # $_

    =~ m/^ERROR\b/ と同じ s/^ERROR\s+//; # $_ を破壊的に書き換える print; # これも $_ 省略 } • 暗黙の$_を使うと急に読みづらくなるが、 慣れてるとサラッと書ける
  66. 正規表現 > PCRE 130 • Perl Compatible Regular Expressions •

    CライブラリとしてPerl以外からでも使えるよ うに ◦ grep -PとかPHPとかに輸出されている
  67. テスト 133 use Test2::V0; 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;
  68. テスト 134 $ prove -lv t/Person.t .. # Seeded srand

    with seed '20251114' from local date. ok 1 - 最初は18歳 ok 2 - incr_age 呼んだら19歳 1..2 ok All tests successful. Files=1, Tests=2, 0 wallclock secs ( 0.00 usr 0.00 sys + 0.02 cusr 0.00 csys = 0.02 CPU) Result: PASS
  69. テスト 135 • テスト結果をTAP形式で表示 ◦ Test Anything Protocol ◦ TAPを読み取って加工するエコシステムがある

    • テストはファイル単位 ◦ .t ファイルが独立している ◦ 分散テスト=テスト対象ファイルを分割するだけ
  70. autovivification 137 my $config = {}; if ($config->{foo}->{bar} eq 'debug')

    { ...; } # autovivification によって $config->{foo} がHashRefに変化 # $config = { foo => { } }
  71. 文字列と数値の区別を付けづらい 138 • 文字列と数値の区別が非常に弱い • 文字列にしたらJSON出力も文字列になる ◦ { "id": "1"

    } ◦ params も DB からの取得も基本は文字列…… • $val+0, $val.'' というテクニック ◦ 数値と計算すると数値に、文字列と結合すると文字列に ◦ JSON::Types という最高のライブラリ
  72. localtimeでコンテキストを間違える 139 • localtime ◦ 現在時刻を取得できる関数 • スカラコンテキスト ◦ Fri

    Nov 14 13:07:32 2025 • リストコンテキスト ◦ (32, 7, 13, 14, 10, '125', 5, 317, 0);
  73. 意図しないカンマ演算子 • my $a = ("a", "b", "c"); は $a

    に "c" が入る • カンマ演算子は複数の式を左から順に評価し、 最後の式の値を返す演算子 ◦ my $x = (print "a", print "b", 100); ◦ ab を出力して $x == 100 になる ◦ 短絡評価のない && みたいな 141
  74. まとめ データ型 リファレンス コンテキスト 演算子 制御 構造 143 サブルーチン モジュール

    オブジェクト指向 入出力 スコープ 特殊変数 UTF-8 正規表現 テスト 罠5選