3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 2

Elixirチートシート番外編その2 変数宣言がないことについて、自分が納得しましたと言うポエム

Last updated at Posted at 2024-12-20

1. Over View

どもども、番外編その2であります

今回、似てるけど、動的型付け vs 静的型付けの話じゃない、ただのポエムであります。

さて、変数のスコープと言えば、変数がアクセス可能な範囲を指します。常識ですね。

これがですね、C言語やJavaで飯を食ってると、変数宣言をして、その変数を使う、ってのが常識な訳でして。
Cでstaticで変数なんか宣言して、別のモジュールから呼び出してみなさいな、IDEだのエディタの限界みたいな
レビューをする羽目になります。

一方、こう言う書き方嫌いだったのね。
for( int i = 0; i < LOOP_MAX ; i++ ) {
iを使った処理
}

変数宣言にコメントが無くて、わかりにくい。反面、下の行見りゃ、iがループの変数だってわかるよね?
その変数が上のforのブロック内で使い終わることわかってるのに、外に出す必要がある?
…などと、ハリネズミのジレンマ的に、自分自身にちくちく来るわけですよ。

なんで、今回は「自分が納得しました」と言う話をしたいと思います。

2. Elixirの変数のスコープについて

以下の三つみたいですね。

スコープの種類 説明
関数スコープ 関数内で定義された変数は、その関数内でのみアクセス可能です。関数が終了すると、変数はスコープ外となり、アクセスできなくなります
ブロックスコープ ブロック(例えば、ifやcaseなど)の内部で定義された変数は、そのブロック内でのみアクセス可能です。ブロックが終了すると、変数はスコープ外となります
モジュールスコープ モジュール内で定義された変数は、そのモジュール内でのみアクセス可能です。モジュール外からはアクセスできません

2.1 関数スコープ

まずは、関数の中でしか、変数は使えないと言うお話

defmodule Example do
  def my_function do
    x = 10
    IO.puts(x)  # 出力: 10
  end # endで終わっているので、xのスコープはここでおしまい。
  def another_function do
    IO.puts(x)  # エラー: xは未定義
  end
end

ほら、怒られたw

warning: redefining module Example (current version defined in memory)
  iex:18: Example (module)

error: undefined variable "x"
  iex:24: Example.another_function/0

** (CompileError) iex: cannot compile module Example (errors have been logged)
    (elixir 1.15.4) src/elixir_module.erl:182: anonymous fn/9 in :elixir_module.compile/7
    iex:18: (file)

2.2 ブロックスコープ

これ、要注意ね。いや、例見りゃ納得出来るだろうけど。

defmodule Example do
  def my_function do
    if true do
      y = 20 # ここでyが初めて使用されてます。
      IO.puts(y)  # 出力: 20
    end # endで終わっているので、yのスコープはここでおしまい。
    IO.puts(y)  # エラー: yは未定義
  end
end

if true do ~ endの内部のブロックで、yが初めて使われております。
なので、endの後には使えませんわな。

ちゃんとエラーになるのを確認してます。

warning: redefining module Example (current version defined in memory)
  iex:18: Example (module)

error: undefined variable "y"
  iex:24: Example.my_function/0

** (CompileError) iex: cannot compile module Example (errors have been logged)
    (elixir 1.15.4) src/elixir_module.erl:182: anonymous fn/9 in :elixir_module.compile/7
    iex:18: (file)

2.3 モジュールスコープ

これはわかりやすいよね。

defmodule Example do
  @module_var 30

  def my_function do
    IO.puts(@module_var)  # 出力: 30
  end
end # ここで、 @module_varはスコープがおしまい。

IO.puts(Example.@module_var)  # エラー: @module_varは未定義

もちろん、エラーなります。

iex(20)> IO.puts(Example.@module_var)  # エラー: @module_varは未定義
error: undefined variable "module_var"
  iex:20

** (CompileError) cannot compile code (errors have been logged)

3. 本日の心の合点ボタン

Elixirで、「変数宣言がなくても、俺自身がどこで解放されてりゃいいか、分かりやすくするコードを意識すればいいんじゃないかな?」と意識を転換しました。
そう気づいた理由が、無名変数の省略記法でして。

これが普通の書き方

sum = fn (a, b) -> a + b end
sum.(2, 3)
5

省略記法

sum = &(&1 + &2)
sum.(2, 3)
5

まー、ファンクション宣言が&()になっちゃうのは驚きましたが、確かに引数、&1や&2でも困らないよね。無名関数なんてのは短く書くもんだしさ。
であれば、変数名もスコープ内で使うものは、別のスコープなら無視すりゃいいんだから、無理に変数宣言にこだわらんでもよくね?

と思った次第です。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?