Ruby のスコープ!

以下の ruby スクリプトを実行するとどうなるでしょう?

#!/usr/bin/env ruby
# coding: utf-8

a = "hoge"

if true
  printf "%s if の中 %s\n", *(["*" * 10] * 2)
  puts "a: #{a}"
  b = "piyo"
  puts "b: #{b}"
end

printf "%s if の外 %s\n", *(["*" * 10] * 2)
puts "a: #{a}"
puts "b: #{b}"

なんと、以下のような結果になります:

********** if の中 **********
a: hoge
b: piyo
********** if の外 **********
a: hoge
b: piyo

“if の中で定義した変数は、if の外からアクセスできないだろう” と思い込んでいたので、ショックでした。

どうしても新しいスコープを開きたければ、proc とかを代用すればいいのかも知れません:

#!/usr/bin/env ruby
# coding: utf-8

a = "hoge"

proc do
  if true
    printf "%s if の中 %s\n", *(["*" * 10] * 2)
    puts "a: #{a}"
    b = "piyo"
    puts "b: #{b}"
  end
end.call

printf "%s if の外 %s\n", *(["*" * 10] * 2)
puts "a: #{a}"
puts "b: #{b}"

実行結果:

********** if の中 **********
a: hoge
b: piyo
********** if の外 **********
a: hoge
hoge.rb:17:in `<main>': undefined local variable or method `b' for main:Object (NameError)

そもそも a とか b とか、簡単に衝突するような安易な変数名を使わなければいいんですけどね!

ちなみに…

Perl の場合:

#!/usr/bin/perl

use strict;
use utf8;

binmode STDOUT, ":utf8";

my $a = "hoge";

if (1) {
  printf("%s if の中 %s\n", (("*" x 10) x 2));
  print "a: $a\n";
  my $b = "piyo";
  print "b: $b\n";
}

printf("%s if の外 %s\n", (("*" x 10) x 2));
print "a: $a\n";
print "b: $b\n";

実行結果:

********** if の中 **********
a: hoge
b: piyo
********** if の外 **********
a: hoge
b: 

perl には my ちゃんがいるので便利ですね。

C の場合:

#include <stdio.h>

int main(void)
{
  char *a = "hoge";

  if (1) {
    char *b = "piyo";
    printf("********** if の中 **********\n");
    printf("%s\n", a);
    printf("%s\n", b);
  }

  printf("********** if の外 **********\n");
  printf("%s\n", a);
  printf("%s\n", b);

  return 0;
}

コンパイルエラーです:

hoge.c: In function ‘main’:
hoge.c:16: error: ‘b’ undeclared (first use in this function)
hoge.c:16: error: (Each undeclared identifier is reported only once
hoge.c:16: error: for each function it appears in.)

python の場合:

#!/usr/bin/python
# coding: utf8

a = "hoge"

if True:
  print "%s if の中 %s" % (("*" * 10,) * 2)
  print "a: " + a
  b = "piyo"
  print "b: " + b

print "%s if の外 %s" % (("*" * 10,) * 2)
print "a: " + a
print "b: " + b

なんと、ruby と同じ挙動です:

********** if の中 **********
a: hoge
b: piyo
********** if の外 **********
a: hoge
b: piyo

php でもやってみました:

<?php

$a = "hoge";

if (true) {
  call_user_func_array("printf", array_merge(array("%s if の中 %s\n"), array_fill(0, 2, str_repeat("*", 10))));
  echo "a: {$a}\n";
  $b = "piyo";
  echo "b: {$b}\n";
}

call_user_func_array("printf", array_merge(array("%s if の外 %s\n"), array_fill(0, 2, str_repeat("*", 10))));
echo "a: {$a}\n";
echo "b: {$b}\n";

ruby, python と同様でした:

********** if の中 **********
a: hoge
b: piyo
********** if の外 **********
a: hoge
b: piyo

スコープも言語によって色々ですね。気づきにくいところなので厄介です。

(コウヅ)

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中