【Scala】「import 変数名._」の使いどころ

##Scalaのimportは任意の場所に記述できる
Scalaの`import`句は概ねJavaのそれと同じような使い方をしますが、いくつか異なる点も存在します。
その内の一つとして、プログラム内の任意の場所(クラス内や関数内など)に記述できることが挙げられます。

```scala
  def absPlus(x: Int, y: Int): Int = {
    import scala.math.abs // ファイルの先頭じゃなくてもいい

    abs(x) + abs(y)
  }
```
参考:
[パッケージとインポート](https://docs.scala-lang.org/ja/tour/packages-and-imports.html)
[Scalaのインポートについてメモ](http://mikamikuh.hatenablog.com/entry/2013/06/20/235831)


##Scalaのimportは「import 変数名._」という書き方もできる
そして実に面白いことに、Scalaでは「<b>スコープ内の変数</b>」に対してもimportすることが可能です。

```scala
  // これを
  def lengthTimes2(str: String): Int = {
    str.length * 2
  }

  // こう書くこともできる！
  def lengthTimes2(str: String): Int = {
    import str.length // 「引数のstrの」lengthをimport
    length * 2        // ここのlengthはstr.lengthと同じもの
  }
```

上記の例では見ての通り、引数に使われている変数`str`に対するimportが行われています。
またファイル先頭で行うimportと同じく、ワイルドカードなどの各種記述も使用可能です。

```scala
  // ワイルドカードも可
  def lengthTimes2(str: String): Int = {
    import str._ 
    length * 2  
  }

  // 別名インポートもできる
  def lengthTimes2(str: String): Int = {
    import str.{length => strLength}
    strLength * 2
  }
```

##「import 変数名._」が使われるケース

上記のような書き方はあくまで「できる」だけであって、実際に上記のような使われ方をすることはまずありません。
ですが、使い道がないというわけでもありません。
例えば、値を`implicit parameter`(暗黙のパラメータ)として渡したいときに活用されていたりします。
どういう風に使われているのか見てみましょう。

###暗黙のパラメータの渡し方
実際の使われ方を見る前に、まず以下のようなクラスを考えてみます。

```scala
// 暗黙のパラメータとしてExecutionContextを受け取るクラス
class Foo(implicit val executionContext: ExecutionContext) {

  val fooFuture = Future {
    ...    // 何らかの処理
  }        // 実際はここで暗黙のパラメータとしてexecutionContextを渡している
}
```

上記では暗黙のパラメータの例として`scala.concurrent.Future`を使用しています。
ここでは`Future`の詳しい説明はしませんが、上記の`Future {}`の部分(※実際には`Future.apply`メソッド)は通常のパラメータ(ブロック式の部分)とは別に、暗黙のパラメータとして`ExecutionContext`を要求します。

```Future.scala
def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]
```

このケースではコンストラクタの時点で既に`ExecutionContext`型の変数を受け取っているので、それを`implicit`にするだけでそのまま`Future.apply`メソッドに(暗黙的に)渡すことができます。
では、以下のようなクラスの場合はどうでしょうか？

```scala
class Bar(foo: Foo) {

  val barFuture = Future {
    ...    // 何らかの処理
  }        // 暗黙のパラメータとして渡すExecutionContextが見つからないためコンパイルエラーとなる
}
```

`Bar`クラスは`Future`の実行コンテクストとして、コンストラクタで受け取った`foo`内の`executionContext`フィールドを使いたいとします。
ですがこの時点では`executionContext`フィールドはスコープ内に存在しないため、`Future.apply`に渡すことはできません。
そのため、上記のコードはコンパイルエラーとなります。

このようなケースの場合、大きく分けて3つの解決策があります。

####1. 暗黙のパラメータを明示的に渡す
何も、暗黙のパラメータに渡すパラメータは必ず暗黙でなければならないというわけではありません。
下記のように、明示的に渡すことも可能です。

```scala
class Bar(foo: Foo) {

  val barFuture = Future {
    ...      // 何らかの処理
  }(foo.executionContext)  // ExecutionContextを明示的に渡す
}
```

可能ではあるのですが、これだと必要とされる度に常に明示的に記述する必要があります。
このようなボイラープレートをなくせるのが暗黙のパラメータのメリットの1つでもあるので、これだとちょっと本末転倒感がありますね。
なのでこの方法はまず採られず、このあと紹介する2.または3.の手法が多く使われています。

####2. スコープ内でimplicitキーワードをつけた変数に代入する
これは、実際にソースを見たほうが早いと思います。

```scala
class Bar(foo: Foo) {

  // Barクラス内でExecutionContext型の変数を改めて定義する(スコープに入る)
  implicit val executionContext: ExecutionContext = foo.executionContext

  val barFuture = Future {
    ...      // 何らかの処理
  }          // 上で定義したExecutionContextを暗黙的に渡す
}
```

見ての通り、`Bar`クラス内で改めて`ExecutionContext`型の変数を宣言しています。
これで`executionContext`がクラス内のスコープに入ったため、クラス内のどこでもこの実行コンテクストを暗黙のパラメータとして渡せるようになります。
強いて問題点を挙げるとすると、`Foo`クラス内の他の暗黙の値も必要とする場合、必要分だけ変数を再定義する手間が生じます。

####3. 対象の暗黙の値を持つ変数をimportする
最後の方法として、ようやく本題ですが、対象の暗黙の値を持つ変数をimportするという手法が挙げられます。
この手法を採用する場合のソースは下記のようになります。

```scala
class Bar(foo: Foo) {
  // 対象の暗黙の値を変数からimportする(executionContextがスコープに入る)
  import foo.executionContext

  val barFuture = Future {
    ...      // 何らかの処理
  }          // foo.executionContextがスコープに入ったので、それを暗黙的に渡している
}
```

このようにimportを使うと、変数`foo`内の`executionContext`フィールドがスコープに入るため、それをそのまま暗黙のパラメータとして使えるようになります。[^1]

今回のようにimportだけで済む場合は、この手法を採用しているケースが多いようです。[^2]

##おわりに
そもそも変数をimportするという事自体がJavaなどのから入った方にとっては衝撃かもしれません。
基本的には暗黙のパラメータ、その中でもいわゆる「[Implicit Contexts](https://www.lihaoyi.com/post/ImplicitDesignPatternsinScala.html#implicit-contexts)」と呼ばれる機能で使われることがある、くらいに考えておけばいいと思います。
自分で書くことがあるかどうかは別として、既存のコードにそういうものがあったときに読めるようになるためにも、この記事がお役に立てれば幸いです。
<br>
最後までお読み頂きありがとうございました｡
質問や不備についてはコメント欄か[Twitter](https://twitter.com/ka2_kamaboko)までお願いします。

[^1]: `executionContext`フィールド自身が`implicit`で定義されている場合に限ります。
[^2]: 例えば[Lightbend](https://www.lightbend.com)の[akka-samples](https://github.com/akka/akka-samples)でも、`ExecutionContext`に関しては変数importを使っています。