2

私はscala、play、およびWebサービスを一度に学んでいるので、我慢してください。天気ウェブサービスとグーグルのジオコードを組み合わせてウェブサービスを配置する小さなアグリゲーターサービスを設定しました。何かが機能していますが、エラーを処理する適切な方法について少し混乱しています。(投稿の最後にコードを投稿しました)

したがって、placesapiはlat/ longを使用するので、geocodeapiを使用して郵便番号からlat/longを取得します。ジオコードAPIの呼び出しからの応答を処理するとき、私は( val(Option[String], Option[String])に保持されている)で終わります。チェックするmaybeLocmatchステートメント内で、最終的には、フラットマップ呼び出しからを返す必要があるため、戻ります。maybeLoc(None, None)Promise()Promise

これについて2つの質問があります。

1.)これらのflatMapまたはmap呼び出しのいずれかで、それ以上の処理を実行できない場合を処理する正しい方法は何ですか?約束を返す必要がありますが、Promise償還するときにタイムアウトするだけの空を作るのは本当に悪い考えのようです。

2.)を呼び出すと、Promise()それを引き換えようとすると常にタイムアウトになる空のPromiseオブジェクトが作成されると想定するのは正しいですか?私はscaladocから本当に言うことができず、グーグルからそれについて何も見つけることができませんでした。

私の質問があなたにとって意味があり、十分に明確であることを願っています。コードは次のとおりです。

def bothAsJson(zipcode:String) = Action {
    val promiseOfLoc = Geocode.buildUrlFor(zipcode).get()
    val promiseOfWeather = Weather.buildUrlFor(zipcode, "json").get()

    val result = promiseOfLoc.flatMap { locResp => 
        val maybeLoc = Geocode.extractLocation(locResp.body.toString())
        maybeLoc match {
            case (Some(lat), Some(lng)) => {
                val promiseOfPlaces = Places.buildUrlFor(lat,lng).get()
                promiseOfPlaces.flatMap { placesResp =>
                    promiseOfWeather.map { weatherResp =>
                        (weatherResp.body.toString(), placesResp.body.toString())
                    }
                }
            }
            case _ => Promise()
        }
    }

    Async {
        result.orTimeout("Timeout!", 2000).map {response =>
            response.fold(
                result => Ok("Got:\n\nweather:\n" + result._1 + "\n\nplaces:\n" + result._2),
                timeout => InternalServerError(timeout)
            )
        }
    }
}
4

1 に答える 1

3

(None、None)が表示された場合は、タイムアウトする必要はありませんが、別のエラーメッセージが返されます。以下に例を示します。

scalaz7のOptionTが必要だと思います。これは次のように記述します。

import scalaz._
import Scalaz._

def bothAsJson(zipcode:String) = Action {
    val promiseOfLoc = Geocode.buildUrlFor(zipcode).get.map { Option(_.body.toString()) }
    val promiseOfWeather = Weather.buildUrlFor(zipcode, "json").get
       .map{ lockResp => 
           val (lat,lng) = Geocode.extractLocation(locResp.body.toString())
           (lat |@| lng).tupled
       }
    def buildPlaces(lat: String, lng: String) = Places.buildUrlFor(lat,lng).get
       .map { Option(_.body.toString) }

    val result = (for {
       (lat, lng) <- OptionT(promiseOfLoc)
       places     <- OptionT(Places.buildUrlFor(lat,lng).get())
       weather    <- OptionT(promiseOfWeather)
    } yield (places, weather)).run

    Async {
        result.orTimeout("Timeout!", 2000).map {response =>
            response.fold(
                result => {
                  result.map(
                   some => Ok("Got:\n\nweather:\n" + some._1 + "\n\nplaces:\n" + some._2)
                  ).getOrElse(BadRequest("lat/lng failed probably?"))
                },
                timeout => InternalServerError(timeout)
            )
        }
    }
}

OptionTを使用すると、それがであるかのようにflatMapを実行Optionでき、Noneを取得した場合に何も処理しないようになります。最後に、Promise[Option[T]]これに非常に適したaが残ります。エラーを処理するもう1つの良い方法は、同じ方法でEither/EtherTを使用することです。

|@|ApplicativeBuilderです。2つのオプションが必要でOption((Int, Int))、両側がの場合はを返しますSome。片側または両側がNoneである場合、それは。を返しますNone

これを機能させるには、scalazMonad[Promise]インスタンスが必要になることに注意してください

implicit val PromiseInstance = new Monad[Promise] {
  // override def map[A,B](fa: Promise[A])(f: A => B) = fa.map(f)
  def point[A](a: => A) = Promise.pure(a)
  def bind[A,B](fa: Promise[A])(f: A => Promise[B]) = fa.flatMap(f)
}

また、このコードはすべてSOエディターで記述したことに注意してください。中括弧が欠落している可能性があります。しかし、すべてのコードは多かれ少なかれ正しいはずです、私はそれの一部をreplでテストしました。

freenodeircの#scalazまたはscalazgoogleグループでお気軽にお問い合わせください。

于 2012-10-01T00:47:55.690 に答える