2017-05-02 12 views
0

関数は、このようなシグネチャを持つ私たちのコードベースにあります:Try for flow controlを使用することをお勧めしますか?

def hasPermission(...): Try[Unit] 

ユーザーが特定のアイテムに特定のアクションを実行する権限を持っている場合、それは基本的にチェックします。ユーザーに許可がある場合は空のSuccessを返し、そうでない場合は特定の例外タイプのFailureを返します。この機能は、多くの場合、このような内包内で使用されています

for { 
    _ <- hasPermission(...) 
    res <- doSomething() 
} yield res 

これは悪い習慣のように思えるが、私はそのように感じ、なぜ私はかなり明確にすることはできません。私には、hasPermissionのように見えるのは、単にBooleanです。

これはTryの適切な使用ですか?

編集:より具体的であるため、私の質問はリンクされたものとは違うと思います。その人はTry [Unit]を返すという一般的な質問をしていますが、私はそれが受け入れられると信じています。

+0

ブール値は、障害の原因ではなく障害が発生したことを伝えるだけです。あなたは失敗を説明する例外を投げることができますが、それが良い練習であるかどうかは議論の対象となります...成功の場合に有用な結果( '')が返されないという事実はほとんど無関係です。 – Jubobs

+1

[[ユニット\]は正しい方法で試していますか?](http://stackoverflow.com/questions/23898507/is-using-tryunit-the-properway) – Jubobs

+0

@mplis正直なところ、 、 どういたしまして。適切に実行されるフロー制御は、通常、モナド/モナド変圧器の組み合わせです。エラー状態を表すために適切な情報量を表現することは常に困難です。https://www.47deg.com/blog/fp-for-the-average-joe-part-2-scalaz-monad-transformers/ 時にはあなたはアプリケーションを望んでいますが、短絡などをしたいときもありますが、一般的な答えはありませんが、コードベースで 'Unit'リターンタイプを見た場合、コードは3秒後に置き換えられます。それは非常にバイナリなアプローチですが、それはそうです。 – flavian

答えて

2

方法がhasPermissionと表示される場合は、BooleanまたはTry[Boolean]を返します。 Try[Unit]Try[Boolean]のようにはっきりしていません。呼び出し元は、例外を調べて、アクセス権がないかどうか、またはアクセス許可情報の取得に失敗したかどうかを判断する必要があります。

これは一般的にはhasPermissionと呼ばれ、その結果に応じて演技することで競争条件が発生する可能性があります(例:hasPermissionが呼び出された後で許可が取り消された場合)。したがって、多くの場合、def doSomething(...): Try[Unit]を実行し、次にa NoPermissionException

0

Generally, the use of exceptions for control flow is an anti-pattern

Tryトライ(しゃれが意図していない)、そのフロー制御をカプセル化するために、しかし、あなたが実際には例外を使用するを必要としない場合は、理由はありません。 Scalaの2.12のEither実装は、おそらく欲しいものに近いようだ:

どちらかがRightが上で動作するデフォルトのケースを想定していることを意味し、右バイアスされています。あなたがウェブサーバを実装していると仮定しましょう、そしてこのロジックは、特定のパスを制御している

type Request = ... 
type Response = String 
type ResponseOr[+T] = Either[Response, T] 

def checkPermission: ResponseOr[Unit] = 
    if(hasPermission) Right(()) 
    else Left("insufficient permissions") 

def doSomething(req: Request): ResponseOr[Something] = 
    if(argumentsAreBad(req)) Left("arguments are bad!") 
    else Right(new Something) 

def makeResponse(result: Something): Response = ??? 

def handleIt(req: Request): Response = { 
    val result = for { 
    _ <- checkPermission 
    result <- doSomething 
    } yield makeResponse(result) 
    result.merge // special method for `Either[T, T]` that gives a `T` 
} 

それはLeftであれば、mapflatMapのような操作はそのままLeft値を返しますSuccessFailureと同様の動作が表示されます - LeftFailureに類似していると思います。フラットマップ/マップステップのいずれかがLeftを返す場合は、それが最終結果ですstはスキップされます。例外は必要ありません。