scala - 用于包装不纯方法的效果?
问题描述
我试图了解如何使用效果单子(cats.effect.IO
或scalaz.IO
无关紧要)。想象一下我有以下方法:
def extract(str: String): String = {
if(str.contains("123"))
"123"
else
throw new IllegalArgumentException("Boom!")
}
由于此方法不纯(抛出异常),我需要将其结果与另一个有效的计算(网络 IO)结合起来,将其包装成IO
如下所示是一个好习惯:
def extract(str: String): IO[String] = IO {
if(str.contains("123"))
"123"
else
throw new IllegalArgumentException("Boom!")
}
它是 Effect monad 的常见用例吗?
解决方案
这是否合适取决于您要表达的内容。
这不像您的第一个def extract(str: String): String
-method 定义在某种程度上是无效的:您只是在地毯下清除所有异常和副作用,因此它们在签名中不可见。如果这与您当前的项目无关,并且如果程序简单地因抛出异常的长堆栈跟踪而崩溃是可以接受的,那么就这样做,没问题(很容易想象一次性的一次性脚本会在哪里合适的)。
相反,如果您声明def extract(str: String): IO[String] = IO { ... }
,那么您至少可以在签名中看到该函数extract
可以做一些不纯的事情(在这种情况下抛出异常)。现在问题变成了:谁负责处理这个异常,或者你想在哪里处理这个异常?考虑一下:如果抛出异常,它将出现在您的代码中yourProgram.unsafeRunSync()
调用类似内容的行中。在那里处理这个异常有意义吗?也许是这样,也许不是:没有人能告诉你。如果你只是想在你的顶层捕获异常main
,记录它,exit
然后它是合适的。
但是,如果您想立即处理异常,您有更好的选择。例如,如果您正在编写一个提示输入文件名的方法,然后尝试extract
从该名称执行某些操作,最后IO
对文件执行一些操作,则返回类型IO[String]
可能太不透明。您可能希望使用其他一些 monad(Option
、Either
等Try
)来表示失败的提取。例如,如果使用Option[String]
作为返回类型,则不再需要在方法中处理千里之外的晦涩异常main
,而是可以立即处理,例如反复提示输入新文件名。
整个练习有点类似于提出一个如何处理一般异常的策略,只是在这里你在方法的类型签名中明确地表达了它。
推荐阅读
- c# - 如何获取游戏对象引用
- c# - 使用 angular4 路由配置 MVC5
- python - TypeError: write() 参数必须是 str,而不是字节
- cron - Hybris 在月底前“x”天运行 cron 作业
- c++ - 使用 mysql-c++-connector 8 将 c++ 连接到 mysql
- javafx - 使用 javafx 中的关键交互修改接口
- azure-data-lake - USQL 文件与托管表 - 如何物理存储数据?
- excel - 用新创建的记录替换第一条记录,而不是在 Excel 工作表中创建新行
- php - 如何使这些数组与 array_diff 函数兼容?
- gradle - Gradle 任务依赖关系:“运行集成测试”与“部署、运行集成测试、终止部署”