Perlのエラーメッセージのコーナー。
Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。
今回のお題は
である。
Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。
今回のお題は
Assignment to both a list and a scalar
である。
これは文ではなく名詞句である。
「リストとスカラー、両方への代入が起こった」という意味だ。
1、3.14、"あいうえお"のような直定数(リテラル)や、$numのようなスカラー変数がこれに入る。
$というシジル(ファニー文字)はScalarのSを取っていると考えると覚えやすい。
scalarという単語は英語で読むとスケイラーになる。
これは数学用語のドイツ語読みに引き摺られて日本ではスカラーと読まれている。
Perlの他にUnicode scalar value(Unicodeの背番号。aはU+0041など)もUnicodeスカラー値と呼ぶことが多い。
これもUnicodeスケイラー値と呼ぶほうが英語の実音に近いと思うが、UnicodeコンソーシアムのターミノロジーでもUnicodeスカラ値となっている。
Unicode Terminology: English - Japanese
リスト(list)は複数のスカラーをカンマで結合したもので、普通カッコに入れて使う。
(1, 2, 3)とか("love", "peace", "forever")とか(6, 5, "Monday")とかである。
Perlはそのままでは二重配列は作れない。
二重配列を作るにはリストのリファレンスというスカラーを作ってリスト要素とする。
リストはスカラーコンテキストとリストコンテキストを持つ。
以下のしょうもないプログラムを考える。
スカラー変数$sclにはスカラーコンテキストの代入が起こりスカラー3が代入された。
ここで3はリストの要素数である。
さて、配列変数にスカラーの代入が出来るだろうか。
出来る。
その後@arr2に4をpushすると、@arr2は2要素のリスト(3, 4)になる。
へー。
さて、配列変数にリストをスカラーコンテキストで代入できる。
何言ってるか分かりますか。
ただ、ゼロを足すのはいかにも分かりにくい.
scalar関数というのを使うと、リストのスカラーコンテキストでの解釈が強制される。
ぐっと見やすい。
そうでもないですか。
C言語でも使えるもので、いかにも頭がいい人が使うっぽい。
ぼくは使わない。
たとえば、以下のようなプログラムを考える。
引数を1個取ってそれが奇数か偶数かを当てる。
でも、いかにも冗長である。
これを条件演算子を使うと短く書けるという。
両方リストのパターンは以下のようなものである。
では、条件が満たされるときはスカラーを、満たされない時はリストを渡すとどうなるだろうか。
受け側が配列なので、代入はリストコンテキストで行われるので、不明瞭ではない。
上のプログラムでは、スカラー$oddか、配列@evenか、どちらに対して代入が行われるのか分からない。
つまり、この代入は、スカラーコンテキストで行われるのか、リストコンテキストになるのか分からないから、エラーを出して終了する。
実行時に判断してもいいような気がするが、それはできないようだ。
「リストとスカラー、両方への代入が起こった」という意味だ。
リストとスカラーとコンテキスト
スカラー(scalar)とは単一の値(数値や文字列)を返す式のことである。1、3.14、"あいうえお"のような直定数(リテラル)や、$numのようなスカラー変数がこれに入る。
$というシジル(ファニー文字)はScalarのSを取っていると考えると覚えやすい。
scalarという単語は英語で読むとスケイラーになる。
これは数学用語のドイツ語読みに引き摺られて日本ではスカラーと読まれている。
Perlの他にUnicode scalar value(Unicodeの背番号。aはU+0041など)もUnicodeスカラー値と呼ぶことが多い。
これもUnicodeスケイラー値と呼ぶほうが英語の実音に近いと思うが、UnicodeコンソーシアムのターミノロジーでもUnicodeスカラ値となっている。
Unicode Terminology: English - Japanese
リスト(list)は複数のスカラーをカンマで結合したもので、普通カッコに入れて使う。
(1, 2, 3)とか("love", "peace", "forever")とか(6, 5, "Monday")とかである。
Perlはそのままでは二重配列は作れない。
二重配列を作るにはリストのリファレンスというスカラーを作ってリスト要素とする。
リストはスカラーコンテキストとリストコンテキストを持つ。
以下のしょうもないプログラムを考える。
#! /usr/bin/perl実行してみる。
#
# contexts.pl
use strict;
use warnings;
use 5.10.0;
my @arr = (1, 4, 8); #リストコンテキストの代入
my $scl = @arr; #スカラーコンテキストの代入
say "\@arr is @arr and \$scl is $scl";
$ contexts.pl配列変数@arrにはリストコンテキストの代入が起こりリスト(1, 4, 8)が代入された。
@arr is 1 4 8 and $scl is 3
スカラー変数$sclにはスカラーコンテキストの代入が起こりスカラー3が代入された。
ここで3はリストの要素数である。
さて、配列変数にスカラーの代入が出来るだろうか。
出来る。
#! /usr/bin/perl実行する。
#
# contexts.pl
use strict;
use warnings;
use 5.10.0;
my @arr = (1, 4, 8); #リストコンテキストの代入
my @arr2 = 3; #スカラーのリストコンテキストの代入
push @arr2, 4;
say "\@arr is @arr and \@arr2 is @arr2";
$ contexts.pl配列@arr2にスカラー値3を入れると、ただ1つの要素を持つリスト(3)で初期化される。
@arr is 1 4 8 and @arr2 is 3 4
その後@arr2に4をpushすると、@arr2は2要素のリスト(3, 4)になる。
へー。
さて、配列変数にリストをスカラーコンテキストで代入できる。
何言ってるか分かりますか。
#! /usr/bin/perlこれでも同じ結果になる。
#
# contexts.pl
use strict;
use warnings;
use 5.10.0;
my @arr = (1, 4, 8); #リストコンテキストの代入
my @arr2 = @arr + 0; #スカラーのリストコンテキストの代入
push @arr2, 4;
say "\@arr is @arr and \@arr2 is @arr2";
$ contexts.pl@arr2に@arrを代入するとき、数値ゼロを加算しているので、スカラーコンテキストになり、要素数3が得られるが、それがリスト(3)として代入され、その結果@arr2は(3)になる。
@arr is 1 4 8 and @arr2 is 3 4
ただ、ゼロを足すのはいかにも分かりにくい.
scalar関数というのを使うと、リストのスカラーコンテキストでの解釈が強制される。
#! /usr/bin/perlこれでも同じ結果になる。
#
# contexts.pl
use strict;
use warnings;
use 5.10.0;
my @arr = (1, 4, 8); #リストコンテキストの代入
my @arr2 = scalar @arr; #スカラーのリストコンテキストの代入
push @arr2, 4;
say "\@arr is @arr and \@arr2 is @arr2";
ぐっと見やすい。
そうでもないですか。
条件演算子
条件演算子「?:」というのがある。条件 ? 成立するときの値 : 不成立の時の値と書く。
C言語でも使えるもので、いかにも頭がいい人が使うっぽい。
ぼくは使わない。
if (条件) {と書く。
成立するときの行動;
} else {
不成立の時の行動;
}
たとえば、以下のようなプログラムを考える。
#! /usr/bin/perl実行する。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my $oddEven;
if ($num % 2 != 0) {
$oddEven = "奇数";
} else {
$oddEven = "偶数";
}
say "$numを入力したね。それは$oddEvenだね";
引数を1個取ってそれが奇数か偶数かを当てる。
$ conditions.pl 1できてるー。
1を入力したね。それは奇数だね
$ conditions.pl 2
2を入力したね。それは偶数だね
でも、いかにも冗長である。
これを条件演算子を使うと短く書けるという。
#! /usr/bin/perl実行してみる。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my $oddEven = ($num % 2 != 0) ? "奇数" : "偶数";
say "$numを入力したね。それは$oddEvenだね";
$ conditions.pl 20同じ動作で、たしかにグッと短くなった。
20を入力したね。それは偶数だね
$ conditions.pl 23
23を入力したね。それは奇数だね
リストを返す条件演算子
このように条件演算子は2つの値になるが、上のはその値が両方「奇数」、「偶数」というスカラーのパターンであった。両方リストのパターンは以下のようなものである。
#! /usr/bin/perl実行する。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my @oddEven = ($num % 2 != 0) ? ("2で割れない", "奇数") : ("2の倍数である", "偶数");
say "$numを入力したね。それは@oddEvenだね";
$ conditions.pl 13この場合、代入はスカラーコンテキストで行われる。
13を入力したね。それは2で割れない 奇数だね
$ conditions.pl 14
14を入力したね。それは2の倍数である 偶数だね
では、条件が満たされるときはスカラーを、満たされない時はリストを渡すとどうなるだろうか。
#! /usr/bin/perlこれでもうまくいく。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my @oddEven = ($num % 2 != 0) ? "奇数" : ("2の倍数である", "偶数");
say "$numを入力したね。それは@oddEvenだね";
$ conditions.pl 15この場合は、スカラー "奇数" を配列に代入すると、("奇数")という1要素のリストになる。
15を入力したね。それは奇数だね
[perl]$ conditions.pl 16
16を入力したね。それは2の倍数である 偶数だね
受け側が配列なので、代入はリストコンテキストで行われるので、不明瞭ではない。
条件演算子が左辺に来る
問題は条件演算子が左辺、代入される側に来る場合である。#! /usr/bin/perlこの場合は、$numが奇数であれば$oddに、偶数であれば$evenに「である」という文字列が入る。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my $odd = "ではない";
my $even = "ではない";
(($num % 2 != 0) ? $odd : $even) = "である"
say "$numを入力したね。それは奇数$oddし、偶数$evenよ!";
$ conditions.pl 101問題は、一方をスカラー、他方をリストにした場合である。
101を入力したね。それは奇数であるし、偶数ではないよ!
$ conditions.pl 102
102を入力したね。それは奇数ではないし、偶数であるよ!
#! /usr/bin/perlこれがうまくいかない。
#
# conditions.pl
use strict;
use warnings;
use 5.10.0;
my $num = shift;
my $odd = "ではない";
my @even = "ではない";
(($num % 2 != 0) ? $odd : @even) = "である";
say "$numを入力したね。それは奇数$oddし、偶数@evenよ!";
$ conditions.pl 2001これがお題のエラーメッセージである。
Assignment to both a list and a scalar at /Users/query1000/perl/conditions.pl line 13, near ""である";"
Execution of /Users/query1000/perl/conditions.pl aborted due to compilation errors.
$ conditions.pl 2002
Assignment to both a list and a scalar at /Users/query1000/perl/conditions.pl line 13, near ""である";"
Execution of /Users/query1000/perl/conditions.pl aborted due to compilation errors.
上のプログラムでは、スカラー$oddか、配列@evenか、どちらに対して代入が行われるのか分からない。
つまり、この代入は、スカラーコンテキストで行われるのか、リストコンテキストになるのか分からないから、エラーを出して終了する。
実行時に判断してもいいような気がするが、それはできないようだ。