문제

스칼라, 플레이, 웹서비스를 한꺼번에 배우고 있으니 양해해주세요.저는 날씨 웹 서비스와 Google의 지리 코드 및 장소 웹 서비스를 결합하는 작은 수집기 서비스를 설정했습니다.뭔가 작동하고 있지만 오류를 처리하는 적절한 방법이 약간 혼란스럽습니다.(게시물 마지막에 코드를 게시했습니다)

따라서 장소 API는 위도/경도를 사용하므로 지리코드 API를 사용하여 우편번호에서 위도/경도를 가져옵니다.지오코드 API 호출의 응답을 처리할 때 다음과 같은 메시지가 표시됩니다. (Option[String], Option[String]) (에서 개최 maybeLoc 발).확인하는 match 문 내부 maybeLoc, 결국 그렇게 된다면 (None, None), 나는 돌아 간다 Promise() 왜냐면 내가 반품을 해야 하거든 Promise 플랫맵 호출에서.

이에 대해 두 가지 질문이 있습니다.

1.) flatMap 또는 map 호출 중 하나에서 추가 처리를 수행할 수 없는 경우를 처리하는 올바른 방법은 무엇입니까?약속을 반환해야 하는데, 약속을 비워야 합니다. Promise 내가 상환하러 갈 때 시간이 초과될 것입니다. 정말 나쁜 생각인 것 같습니다.

2.) 다음을 호출한다고 가정하는 것이 옳습니까? Promise() 그것을 상환하려고 할 때 항상 시간 초과되는 빈 Promise 개체를 만드는가?나는 scaladoc에서 실제로 알 수 없었고 Google에서 그것에 대해 아무것도 찾을 수 없었습니다.

내 질문이 귀하에게 이해가 되고 충분히 명확해지기를 바랍니다.코드는 다음과 같습니다.

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)
            )
        }
    }
}
도움이 되었습니까?

해결책

(None, None)이 표시되면 시간 초과를 기대해서는 안 되지만 다른 오류 메시지를 반환해야 한다고 생각합니다.아래에 예를 제시했습니다.

Scalaz 7의 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]] 이것은 매우 좋습니다.오류를 처리하는 또 다른 좋은 방법은 동일한 방법으로 EtherT/EtherT를 사용하는 것입니다.

|@| Applicative Builder입니다.2개의 옵션이 필요하며 Option((Int, Int)) 양측이 그렇다면 Some.한쪽 또는 양쪽이 모두 있는 경우 None, 이는 다음을 반환합니다. None.

이것이 작동하려면 scalaz가 필요합니다. Monad[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에서 테스트했습니다.

freenode irc의 #scalaz나 scalaz google 그룹에 언제든지 도움을 요청하세요.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top