7

OptionNullPointerException を回避するのに役立つクラスについて読んだ記事の結果として、あらゆる場所でこのクラスを使用するようになりました。次のようなものを想像してください。

var file:Option[File] = None

後で私がそれを使用するとき:

val actualFile = file.getOrElse(new File("nonexisting"))
if(actualFile.getName.equals("nonexisting")) { // instead of null checking

}
else { // value of file was good

}

このようなことをすることは、私にとってそれほど「正しい」とは感じません。.getまた、非推奨になっていることに気付きました。. この種のことは、皆さんが Option でも行っていることですか、それとも間違った方向に進んでいますか?

4

5 に答える 5

15

通常、返してから、「見つからない」ことを意味するセンチネル値を生成するためOptionに使用することはお勧めできません。値が見つからないことを示すために設計されていますgetOrElseOption

Optionmapや などの関数型プログラミング構成要素と組み合わせて使用​​すると、その力が本当に発揮されforeachます。これは、複数のオプションを扱う場合に最も強力です。たとえば、ファイルが存在し、ディレクトリではなくファイルである場合にのみ、文字列を取得してファイルを返すメソッドを作成するとします。

import java.io._;
def niceFile1(s: String): File = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) f else null
}
def niceFile2(s: String): Option[File] = {
  val f = new File(s);
  if (f.exists && !f.isDirectory) Some(f) else None
}

これまでのところ、使用するnull方が簡単です。少なくとも、これが原因nullで NPE が発生する可能性があることを忘れるまでは。ともあれ、さっそく使ってみましょう。

def niceFopen1(s: String) = {
  val f = niceFile1(s);
  if (f!=null) new FileInputStream(f) else null;
}
def niceFopen2(s: String) = niceFile2(s).map(f => new FileInputStream(f))

何が起こったのか見てください!前者の場合、手動でロジック テストを行い、一時変数を作成する必要がありました。うーん!2 番目のケースでmapは、すべての面倒な作業を行いました。None は None にマップされ、Some(file)にマップされましたSome(fileinputstream)。簡単!

しかし、それはさらに良くなります。たぶん、たくさんのファイルのサイズを見つけたいと思うでしょう:

def totalSize2(ss: Seq[String]) = {
  (0L /: ss.flatMap(niceFile2)){(sum,f) => sum+f.length}
}

待ってください、ここで何が起こっているのNoneですか? 注意して何とかしないといけませんか?ここで、flatMapすべての回答を 1 つのリストに結合します。 Noneは長さ 0 の回答であるため、無視されます。 Some(f)答えは 1 つなのでf、リストに入れます。次に、フォールドを使用してすべての長さを合計します。これで、リスト内のすべての要素が有効になります。かなりいい!

于 2010-03-19T14:30:10.517 に答える
12

の値を解決するのではなく、含まれるものにロジックをOption適用することをお勧めします。

findFile.foreach(process(_))

基本的に、これは aFileが見つかった場合に処理し、それ以外の場合は何もしません (また、への呼び出しにコンパイルされるforため、Thomas の最初の理解と同等です)。これは、次のより簡潔なバージョンです。forforeach

findFile match {
  case Some(f) => process(f)
  case None =>
}

さらに、これの素晴らしい点は、次のような操作を連鎖できることです。

(findLiveFile orElse fileBackupFile orElse findTempFile).foreach(process(_)
于 2010-03-19T12:30:30.690 に答える
7

ほとんどの場合、パターン マッチングを使用します。

file match {
   case Some(f) => { .. } //file is there
   case _ => { .. } //file is not there 
}

ファイルが存在する場合にのみファイルに関心がある場合は、 for 式を使用できます

for(f <- file) { //file is there 
}

その後、コンテナの複数のレベルで動作するように式をチェーンできます

for{ 
  option <- List(Some(1), None, Some(2))
  f <- option
} yield f

res0: List[Int] = List(1, 2)

または、 isDefined を使用して取得することもできます。

if(option.isDefined) {
   val x = option.get;
} else {
}

get は Scala 2.8.0.Beta-1 では非推奨ではありません。

于 2010-03-19T11:45:03.277 に答える
2

代替案は次のとおりです。

var file:Option[File] = None
// ...
file map (new File(_)) foreach { fh =>
  // ...
}

ただし、ファイルが存在する場合は何かを行う必要があり、存在しない場合は別のことを行う必要がある場合は、次のmatchステートメントがより適切です。

var file:Option[File] = None
// ...
file map (new File(_)) match {
  case Some(fh) =>
    // ...
  case None =>
    // ...
}

それはステートメントとほとんど同じですが、値を抽出したいifのようなものでは、自然を連鎖させる方が良いと思います。Option

于 2010-03-19T12:49:37.657 に答える
1

ほとんどの人が言っていることを言い換えますが、次のような nullable var がある場合に遭遇する状況は少なくとも 4 つあります。

1. ファイルはヌルであってはなりません

load(file.get())

実際にファイルを使用しようとすると、例外がスローされます。はやく失敗しろよ!

2. ファイルは null ですが、この場合は適切なデフォルトがあります。

load(file.getOrElse(new File("/defaultFile")))

3. ファイルが存在するかどうかに基づくロジックの 2 つのブランチ:

  file match {
    case Some(f) => { .. } //file is there
    case _ => { .. } //file is not there 
  }

4. ファイルが null の場合はノーオペレーション、つまりサイレントに失敗します。私はこれが実生活で私にとって非常に頻繁に好ましいとは思わない:

for (f <- file) {
//do some stuff
}

それとも、もっと明確に?

if (f.isDefined) {
  //do some stuff
}
于 2010-03-19T15:14:50.100 に答える