首页 > 解决方案 > 如何处理 scala.js 外观中的可为空值?

问题描述

我正在尝试为请求库编写一个 Scalajs 外观,它有一个使用回调模式的方法:

request('http://www.google.com', function (error, response, body) {
  console.log('error:', error); // Print the error if one occurred
  console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
  console.log('body:', body); // Print the HTML for the Google homepage.
});

在此模式中,要么error为空,response要么body已定义,反之亦然。

在 ScalaJS 外观中反映这种模式的最佳方式是什么?我能想到的最好的是:

@js.native
@JSImport("request", JSImport.Default)
object Request extends js.Object {
  def apply[A](uri: String,
               requestConfig: js.Object,
               callback: js.Function2[js.JavaScriptException, Response, A]): Unit = js.native
}

执行该方法后,我使用它Option来匹配正确的大小写:

Request(url, RequestConfig(queryString, headers), (error, response) => {
  (Option(error), Option(response)) match {
    case (Some(err), _) => // handle error
    case (_, Some(res)) => // handle success
    case (None, None) => // This will only happen if there is a bug in the request library
  }
})

我不喜欢这样,因为 1)我必须为非详尽匹配警告编写不必要的匹配(None, None)或忽略非详尽匹配警告,以及 2)外观没有准确描述类型。

我也尝试过使用js.UndefOr[js.JavaScriptException],但这会返回 a Some(null)from .toOptionjs.JavaScriptException | Null但我似乎只能将其转换为Option[js.JavaScriptException | Null].

标签: scala.js

解决方案


不同undefined的是,Scala.js 没有给你特殊的工具来处理null

这是因为在 Scala 中一切都是可以为空的(我们中的许多人不喜欢这个事实,包括我自己,但这是一个不同的讨论)。

因此,我们必须争辩说,外观确实使用 Scala / Scala.js 类型系统尽可能准确地描述了类型。

如果您需要经常使用它,@Thilo 建议的包装器确实是您的最佳选择:

object RichRequest {
  def apply(uri: String, req: RequestConfig): Future[Response] = {
    val p = Promise[Response]()
    Request(uri, req, (error, response) => {
      if (error != null) p.failure(error)
      else p.success(response)
    })
    p.future
  }
}

或者,如果您想保持 API 回调为基础,请考虑使用Try.

请注意,如果您想沿着这条路走下去,请考虑使用request-promise-native来获得它(使用 JavaScript 承诺)。

所以你的门面会变成:

@js.native
@JSImport("request-promise-native", JSImport.Default)
object Request extends js.Object {
  def apply(uri: String, requestConfig: js.Object): js.Promise[Response] = js.native
}

和呼叫站点:

Request(url, RequestConfig(...)).toFuture

推荐阅读