Featured image of post Perlコンテキストの魔法 - スカラー・リスト・voidコンテキストを理解する

Perlコンテキストの魔法 - スカラー・リスト・voidコンテキストを理解する

Perlの最も重要な概念「コンテキスト」を完全理解。スカラー・リスト・voidコンテキストの違いと、wantarray()を使った柔軟な関数実装を学びます

Perlコンテキストとは何か

Perlを学ぶ上で避けて通れない、しかし理解すると世界が広がる概念が「コンテキスト(context)」です。

コンテキストとは、式や変数がどのような状況で評価されるかを示すものです。同じ式でも、評価されるコンテキストによって返される値が変わります。これはPerlの「TMTOWTDI(There’s More Than One Way To Do It)」の精神を支える重要な仕組みです。

Perlには主に3つのコンテキストがあります:

  • スカラーコンテキスト(Scalar Context): 単一の値を期待する状況
  • リストコンテキスト(List Context): 複数の値を期待する状況
  • voidコンテキスト(Void Context): 戻り値を使わない状況

この記事では、これらのコンテキストを完全に理解し、実践的に活用する方法を学んでいきます。

スカラーコンテキスト

スカラーコンテキストは、単一の値(スカラー値)を期待する状況です。

スカラーコンテキストが発生する場面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 代入の右辺でスカラー変数に代入
my $count = @array;  # 配列の要素数が入る

# if文の条件式
if (@array) {  # 要素数が真偽値として評価される
    print "配列に要素があります\n";
}

# 文字列連結
my $str = "要素数は " . @array;  # 配列が要素数に変換される

# 数値演算
my $result = @array + 10;  # 配列の要素数 + 10

配列のスカラーコンテキスト

配列をスカラーコンテキストで評価すると、要素数を返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
my @fruits = ('apple', 'banana', 'cherry');

my $count = @fruits;  # $count = 3
print "果物の種類: $count\n";  # 果物の種類: 3

# 真偽値としての評価(要素数が0なら偽、それ以外は真)
if (@fruits) {
    print "果物があります\n";
}

my @empty = ();
if (!@empty) {
    print "空の配列です\n";
}

これは非常に便利で、配列が空かどうかをチェックする時によく使われます:

1
2
3
4
5
6
7
8
9
# 良い書き方
if (@array) {
    # 配列に要素がある
}

# 冗長な書き方(避けるべき)
if (scalar(@array) > 0) {
    # 配列に要素がある
}

ハッシュのスカラーコンテキスト

ハッシュをスカラーコンテキストで評価すると、少し特殊な値を返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
my %hash = (a => 1, b => 2, c => 3);

my $scalar = %hash;
print $scalar, "\n";  # 例: "3/8" (使用バケット数/総バケット数)

# 真偽値としての評価(要素があれば真、空なら偽)
if (%hash) {
    print "ハッシュに要素があります\n";
}

my %empty = ();
if (!%empty) {
    print "空のハッシュです\n";
}

ハッシュのスカラー評価は、主に空かどうかの判定に使われます。バケット情報は通常は気にしません。

正規表現のスカラーコンテキスト

正規表現マッチングのスカラーコンテキストは、**マッチしたかどうか(真偽値)**を返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
my $text = "Hello, World!";

# スカラーコンテキスト: マッチの成否
if ($text =~ /World/) {
    print "マッチしました\n";
}

# マッチした文字列を取得したい場合
if ($text =~ /(W\w+)/) {
    my $matched = $1;  # "World"
    print "マッチした単語: $matched\n";
}

リストコンテキスト

リストコンテキストは、複数の値を期待する状況です。これがPerlの強力さの源泉の一つです。

リストコンテキストが発生する場面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 配列への代入
my @array = function();  # function()はリストコンテキストで評価される

# リストへの代入
my ($x, $y, $z) = function();  # 複数の値を受け取る

# foreach ループ
foreach my $item (function()) {  # リストを反復処理
    print "$item\n";
}

# 関数の引数(括弧内)
print function();  # function()の結果をすべて表示

# 配列の初期化
my @result = (1, 2, function(), 3);  # function()の結果が展開される

配列のリストコンテキスト

配列をリストコンテキストで評価すると、全要素のリストを返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
my @fruits = ('apple', 'banana', 'cherry');

# 別の配列にコピー
my @copy = @fruits;  # ('apple', 'banana', 'cherry')

# 配列の要素を展開
my @combined = ('orange', @fruits, 'grape');
# ('orange', 'apple', 'banana', 'cherry', 'grape')

# foreach で反復処理
foreach my $fruit (@fruits) {
    print "$fruit\n";
}

ハッシュのリストコンテキスト

ハッシュをリストコンテキストで評価すると、キーと値のペアのリストを返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
my %person = (
    name => 'Alice',
    age  => 30,
    city => 'Tokyo',
);

# リストとして展開
my @list = %person;
# ('name', 'Alice', 'age', 30, 'city', 'Tokyo')
# 順序は保証されない!

# 別のハッシュにコピー
my %copy = %person;

# ハッシュのマージ
my %merged = (%person, job => 'Engineer');

重要: ハッシュをリストに展開した時の順序は保証されません。内部のハッシュ関数の実装に依存します。

正規表現のリストコンテキスト

正規表現マッチングのリストコンテキストは、キャプチャされた値のリストを返します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
my $text = "2025-12-08";

# リストコンテキスト: キャプチャされた値のリスト
my ($year, $month, $day) = $text =~ /(\d{4})-(\d{2})-(\d{2})/;
print "年: $year, 月: $month, 日: $day\n";
# 年: 2025, 月: 12, 日: 08

# グローバルマッチ
my @words = "apple banana cherry" =~ /(\w+)/g;
# @words = ('apple', 'banana', 'cherry')

# マッチしなかった場合は空リスト
my @no_match = "abc" =~ /(\d+)/;
# @no_match = ()

これは非常に強力で、テキスト処理でよく使われるイディオムです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# CSVのような形式をパース
my $line = "Alice,30,Tokyo";
my ($name, $age, $city) = split /,/, $line;

# URLからパラメータを抽出
my $url = "http://example.com/user/123";
if ($url =~ m{/user/(\d+)}) {
    my $user_id = $1;
    print "User ID: $user_id\n";
}

voidコンテキスト

voidコンテキストは、式の戻り値が使われない状況です。

1
2
3
4
5
6
7
8
# 関数呼び出しの結果を使わない
function();  # voidコンテキスト

# 代入文全体(代入の結果は使われない)
$x = 10;  # voidコンテキスト

# 式の結果を捨てる
@array;  # voidコンテキスト(意味はない)

voidコンテキストでは、一部の演算子は警告を出すことがあります:

1
2
3
4
5
6
7
8
use warnings;

# 警告: Useless use of hash in void context
%hash;

# 警告が出ない(副作用がある)
print "Hello\n";  # 出力という副作用がある
push @array, 1;   # 配列を変更する副作用がある

コンテキストを明示的に指定する

Perlには、コンテキストを明示的に指定する関数があります。

scalar() 関数

scalar() は、引数を強制的にスカラーコンテキストで評価します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
my @array = (1, 2, 3, 4, 5);

# リストコンテキストで評価(配列の要素をコピー)
my @copy = @array;  # (1, 2, 3, 4, 5)

# スカラーコンテキストで評価(要素数を取得)
my $count = scalar @array;  # 5

# 例: ハッシュのキーの数を取得
my %hash = (a => 1, b => 2, c => 3);
my $key_count = scalar keys %hash;  # 3

リストコンテキストの強制

リストコンテキストを強制する組み込み関数はありませんが、配列に代入することで実現できます:

1
2
3
4
5
6
7
8
# スカラー変数に配列を代入(スカラーコンテキスト)
my $x = @array;  # 要素数

# 配列変数に配列を代入(リストコンテキスト)
my @y = @array;  # 全要素のコピー

# リストを括弧で囲んでもリストコンテキストになる
my ($z) = @array;  # 最初の要素だけを取得

最後の例は重要です:

1
2
3
4
5
6
7
my @values = (10, 20, 30);

# スカラーコンテキスト
my $first = @values;  # 3(要素数)

# リストコンテキスト(最初の要素だけを取得)
my ($first) = @values;  # 10

wantarray() による柔軟な関数実装

wantarray() は、関数が呼び出されたコンテキストを判定する特殊な関数です。

wantarray() の戻り値

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
sub context_aware {
    if (wantarray) {
        # リストコンテキストで呼ばれた
        return ('list', 'context');
    } elsif (defined wantarray) {
        # スカラーコンテキストで呼ばれた
        return 'scalar context';
    } else {
        # voidコンテキストで呼ばれた
        print "void context\n";
        return;
    }
}

# テスト
my @list = context_aware();     # @list = ('list', 'context')
my $scalar = context_aware();   # $scalar = 'scalar context'
context_aware();                # 出力: void context

実用的な例1: ファイル読み込み

組み込みの <> 演算子も、コンテキストに応じて動作が変わります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# スカラーコンテキスト: 1行だけ読む
my $line = <STDIN>;

# リストコンテキスト: 全行を読む
my @lines = <STDIN>;

# これを自分で実装すると:
sub read_file {
    my ($filename) = @_;
    open my $fh, '<', $filename or die "Cannot open $filename: $!";
    
    if (wantarray) {
        # リストコンテキスト: 全行を返す
        my @lines = <$fh>;
        close $fh;
        return @lines;
    } else {
        # スカラーコンテキスト: 最初の行だけ返す
        my $line = <$fh>;
        close $fh;
        return $line;
    }
}

# 使用例
my $first_line = read_file('data.txt');  # 最初の行だけ
my @all_lines = read_file('data.txt');   # 全行

実用的な例2: データベースクエリ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
sub fetch_users {
    my ($dbh, $condition) = @_;
    
    my $sth = $dbh->prepare("SELECT * FROM users WHERE $condition");
    $sth->execute();
    
    if (wantarray) {
        # リストコンテキスト: 全レコードを返す
        my @users;
        while (my $row = $sth->fetchrow_hashref) {
            push @users, $row;
        }
        return @users;
    } else {
        # スカラーコンテキスト: 最初の1件だけ返す
        return $sth->fetchrow_hashref;
    }
}

# 使用例
my $user = fetch_users($dbh, "id = 1");     # 1件だけ取得
my @users = fetch_users($dbh, "age > 20"); # 全件取得

実用的な例3: 検索関数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
sub find_items {
    my ($pattern, @items) = @_;
    
    my @matches = grep { /$pattern/ } @items;
    
    if (wantarray) {
        # リストコンテキスト: マッチした全要素を返す
        return @matches;
    } elsif (defined wantarray) {
        # スカラーコンテキスト: マッチした個数を返す
        return scalar @matches;
    } else {
        # voidコンテキスト: 何もしない(警告を出すこともできる)
        warn "find_items called in void context";
        return;
    }
}

# 使用例
my @found = find_items('perl', @files);   # マッチしたファイル名のリスト
my $count = find_items('perl', @files);   # マッチした個数
find_items('perl', @files);               # 警告が出る

実用的な例4: 統計関数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
sub analyze_numbers {
    my (@numbers) = @_;
    
    return unless @numbers;
    
    my $sum = 0;
    $sum += $_ for @numbers;
    my $avg = $sum / @numbers;
    
    my @sorted = sort { $a <=> $b } @numbers;
    my $min = $sorted[0];
    my $max = $sorted[-1];
    my $median = @sorted % 2 
        ? $sorted[@sorted/2]
        : ($sorted[@sorted/2-1] + $sorted[@sorted/2]) / 2;
    
    if (wantarray) {
        # リストコンテキスト: 詳細な統計情報を返す
        return (
            sum    => $sum,
            avg    => $avg,
            min    => $min,
            max    => $max,
            median => $median,
            count  => scalar @numbers,
        );
    } else {
        # スカラーコンテキスト: 平均値のみを返す
        return $avg;
    }
}

# 使用例
my @data = (10, 20, 30, 40, 50);

my $average = analyze_numbers(@data);  # 30
my %stats = analyze_numbers(@data);    # 詳細な統計情報
print "平均: $stats{avg}, 中央値: $stats{median}\n";

コンテキストと演算子

多くのPerlの演算子は、コンテキストによって動作が変わります。

代入演算子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
my @array = (1, 2, 3);

# スカラーコンテキスト
my $x = @array;  # $x = 3(要素数)

# リストコンテキスト
my @y = @array;  # @y = (1, 2, 3)

# リストの最初の要素だけを取得
my ($first) = @array;  # $first = 1

range演算子 (..)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# リストコンテキスト: 範囲のリストを生成
my @numbers = (1..10);  # (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

# スカラーコンテキスト: フリップフロップ演算子として動作
# (行範囲演算子として使われることが多い)
while (<DATA>) {
    print if /START/ .. /END/;  # STARTからENDまでの行を出力
}

__DATA__
header
START
line1
line2
END
footer

reverse関数

1
2
3
4
5
6
7
8
my @array = (1, 2, 3, 4, 5);

# リストコンテキスト: 配列の順序を逆にする
my @reversed = reverse @array;  # (5, 4, 3, 2, 1)

# スカラーコンテキスト: 文字列を逆にする
my $str = "Hello";
my $reversed_str = reverse $str;  # "olleH"

これは注意が必要です:

1
2
3
4
5
6
7
my @array = (1, 2, 3);

# これは期待通りに動作しない!
my $result = reverse @array;  # $result = "321"(文字列として連結される)

# 配列を逆順にしたい場合は、明示的にリストコンテキストで
my @reversed = reverse @array;  # (3, 2, 1)

sort関数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
my @numbers = (5, 2, 8, 1, 9);

# リストコンテキスト: ソートされた配列を返す
my @sorted = sort { $a <=> $b } @numbers;  # (1, 2, 5, 8, 9)

# スカラーコンテキスト: 最初の要素を返す
my $first = sort { $a <=> $b } @numbers;  # 1

# ただし、スカラーコンテキストでsortを使うのは非効率
# なぜなら、内部では全要素をソートしてから最初の要素だけを返すため

map と grep

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
my @numbers = (1, 2, 3, 4, 5);

# リストコンテキスト: 変換/フィルタされた配列を返す
my @doubled = map { $_ * 2 } @numbers;     # (2, 4, 6, 8, 10)
my @evens = grep { $_ % 2 == 0 } @numbers; # (2, 4)

# スカラーコンテキスト: 要素数を返す
my $count = grep { $_ % 2 == 0 } @numbers; # 2(偶数の個数)

# mapのスカラーコンテキストは注意が必要
my $last = map { $_ * 2 } @numbers;  # 10(最後の要素)
# これは分かりにくいので避けるべき

よくある誤解と落とし穴

誤解1: 配列代入は常にコピーする

1
2
3
4
5
6
7
8
9
my @original = (1, 2, 3);

# これはコピー
my @copy = @original;
$copy[0] = 999;
print $original[0];  # 1(変更されない)

# これも実はコピー(リファレンスではない)
my $ref = \@original;  # これがリファレンス

誤解2: スカラー変数に配列を代入すると最初の要素が入る

1
2
3
4
5
6
7
8
9
my @array = (1, 2, 3);

# 誤解: 最初の要素が入ると思う
my $x = @array;  # $x = 3(要素数)

# 最初の要素を取りたい場合
my ($first) = @array;     # $first = 1
# または
my $first = $array[0];    # $first = 1

誤解3: ハッシュのスカラー評価で要素数が取れる

1
2
3
4
5
6
7
my %hash = (a => 1, b => 2, c => 3);

# ハッシュのスカラー評価は要素数ではない!
my $x = %hash;  # "3/8" のようなバケット情報

# 要素数が欲しい場合はkeys()を使う
my $count = scalar keys %hash;  # 3

落とし穴1: リストのフラット化

Perlのリストは常にフラット化されます:

1
2
3
4
5
6
7
8
9
my @a = (1, 2);
my @b = (3, 4);
my @c = (@a, @b);  # (1, 2, 3, 4) - フラット化される

# 多次元配列を作りたい場合はリファレンスを使う
my @matrix = (
    [1, 2],
    [3, 4],
);

落とし穴2: 関数の引数は常にフラット化される

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
sub print_arrays {
    my (@arr1, @arr2) = @_;  # これは期待通りに動作しない!
    # @arr1 がすべての引数を受け取り、@arr2 は空になる
}

my @a = (1, 2);
my @b = (3, 4);
print_arrays(@a, @b);  # @arr1 = (1, 2, 3, 4), @arr2 = ()

# 複数の配列を渡したい場合はリファレンスを使う
sub print_arrays_correct {
    my ($arr1_ref, $arr2_ref) = @_;
    my @arr1 = @$arr1_ref;
    my @arr2 = @$arr2_ref;
    # ...
}
print_arrays_correct(\@a, \@b);

落とし穴3: 正規表現のグローバルマッチ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
my $text = "apple banana cherry";

# スカラーコンテキストでのグローバルマッチは反復的に動作する
while ($text =~ /(\w+)/g) {
    print "Found: $1\n";
}
# Found: apple
# Found: banana
# Found: cherry

# リストコンテキストでは一度に全部マッチする
my @words = $text =~ /(\w+)/g;
# @words = ('apple', 'banana', 'cherry')

落とし穴4: voidコンテキストでの警告

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use warnings;

my @array = (1, 2, 3);

# 警告: Useless use of array in void context
@array;

# これも同様
my %hash = (a => 1);
%hash;  # 警告

# 副作用がある式なら警告は出ない
print @array;  # OK(出力という副作用がある)

実践的なコンテキスト活用パターン

パターン1: 柔軟なゲッター

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package User;
use strict;
use warnings;

sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}

sub roles {
    my $self = shift;
    
    if (wantarray) {
        # リストコンテキスト: ロールのリストを返す
        return @{$self->{roles} || []};
    } else {
        # スカラーコンテキスト: ロールの数を返す
        return scalar @{$self->{roles} || []};
    }
}

# 使用例
my $user = User->new(roles => ['admin', 'editor', 'user']);

my @roles = $user->roles;  # ('admin', 'editor', 'user')
my $count = $user->roles;  # 3

if ($user->roles > 1) {
    print "複数のロールを持っています\n";
}

パターン2: スマートな検索

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
sub search {
    my ($pattern, $data_ref) = @_;
    
    my @results;
    for my $item (@$data_ref) {
        if ($item =~ /$pattern/) {
            if (wantarray) {
                # リストコンテキスト: マッチした項目を収集
                push @results, $item;
            } else {
                # スカラーコンテキスト: 最初のマッチを即座に返す
                return $item;
            }
        }
    }
    
    return wantarray ? @results : undef;
}

# 大きなデータセット
my @data = (1..1_000_000);

# 最初の1件だけ欲しい(効率的)
my $first = search(qr/^999/, \@data);

# 全件欲しい
my @all = search(qr/^999/, \@data);

パターン3: 設定の取得

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package Config;
use strict;
use warnings;

my %config = (
    database => {
        host => 'localhost',
        port => 5432,
        name => 'mydb',
    },
    cache => {
        enabled => 1,
        ttl => 3600,
    },
);

sub get {
    my ($class, $key) = @_;
    
    my $value = $config{$key};
    
    if (ref $value eq 'HASH') {
        if (wantarray) {
            # リストコンテキスト: ハッシュをキー・値のリストとして返す
            return %$value;
        } else {
            # スカラーコンテキスト: ハッシュリファレンスを返す
            return $value;
        }
    }
    
    return $value;
}

# 使用例
my %db_config = Config->get('database');  # ハッシュとしてコピー
my $db_ref = Config->get('database');     # リファレンスとして取得

my $host = $db_ref->{host};

パターン4: 日時の解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use Time::Piece;

sub parse_datetime {
    my ($str) = @_;
    
    my $t = Time::Piece->strptime($str, '%Y-%m-%d %H:%M:%S');
    
    if (wantarray) {
        # リストコンテキスト: 年月日時分秒を個別に返す
        return ($t->year, $t->mon, $t->mday, 
                $t->hour, $t->min, $t->sec);
    } else {
        # スカラーコンテキスト: Time::Pieceオブジェクトを返す
        return $t;
    }
}

# 使用例
my $dt = parse_datetime('2025-12-08 15:30:45');
print $dt->strftime('%Y年%m月%d日');

my ($year, $month, $day, $hour, $min, $sec) 
    = parse_datetime('2025-12-08 15:30:45');
print "年: $year, 月: $month, 日: $day\n";

まとめ

Perlのコンテキスト概念は、最初は戸惑うかもしれませんが、理解すると非常に強力なツールになります。

重要なポイント

  1. 3つのコンテキスト

    • スカラーコンテキスト: 単一の値を期待
    • リストコンテキスト: 複数の値を期待
    • voidコンテキスト: 戻り値を使わない
  2. 配列とハッシュ

    • 配列のスカラー評価 = 要素数
    • ハッシュのスカラー評価 = バケット情報(通常は気にしない)
    • 空チェックには if (@array)if (%hash) が便利
  3. 正規表現

    • スカラーコンテキスト = マッチの成否(真偽値)
    • リストコンテキスト = キャプチャされた値のリスト
  4. wantarray()

    • リストコンテキスト: 真を返す
    • スカラーコンテキスト: 定義された偽を返す
    • voidコンテキスト: 未定義値を返す
  5. 実用的なパターン

    • wantarray() を使って柔軟な関数を実装
    • スカラーコンテキストでは簡潔な値を返す
    • リストコンテキストでは詳細な情報を返す

コンテキストを意識したコーディング

Perlのコンテキストを理解することで、より表現力豊かなコードが書けるようになります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# コンテキストを活かした美しいコード
my @sorted = sort { $a <=> $b } @numbers;  # リストコンテキスト
my $count = grep { $_ > 10 } @numbers;     # スカラーコンテキスト

# 配列の空チェック
if (@array) { ... }

# 最初の要素を取得
my ($first) = @array;

# wantarray()で柔軟な関数
sub flexible_function {
    return wantarray ? (1, 2, 3) : 3;
}

コンテキストはPerlの魔法の一つです。この概念を使いこなせば、あなたのPerlコードはより洗練され、表現力豊かなものになるでしょう!

Happy Coding! 🎄

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。