【问题标题】:Are there any types with side-effecting methods that return the original type?是否有任何类型具有返回原始类型的副作用方法?
【发布时间】:2014-11-03 13:15:03
【问题描述】:

我经常发现自己想以一种更具功能性的方式将一个副作用函数链接到另一个方法调用的末尾,但我不想将原始类型转换为Unit。假设我有一个 read 方法在数据库中搜索记录,返回 Option[Record]

def read(id: Long): Option[Record] = ...

如果read 返回Some(record),那么我可能想要缓存该值并继续前进。我可以这样做:

read(id).map { record =>
    // Cache the record
    record
}

但是,我想避免使用上面的代码,并以类似这样的方式结束,以便更清楚地了解正在发生的事情:

read(id).withSideEffect { record =>
    // Cache the record
}

其中withSideEffect 返回与read(id) 相同的值。在搜索了高低之后,我找不到任何类型的方法来做这样的事情。我能想出的最接近的解决方案是使用隐式魔法:

implicit class ExtendedOption[A](underlying: Option[A]) {
    def withSideEffect(op: A => Unit): Option[A] = {
        underlying.foreach(op)
        underlying
    }
}

是否有任何 Scala 类型我可能忽略了像这样的方法?使用这种方法是否存在任何潜在的设计缺陷?

【问题讨论】:

  • Scala 确实支持“单例类型”(不要与对象混淆),这是对应于特定实例的类型。例如方法def f(a: A): a.type必须返回A提供的实例。
  • 我觉得设计不错,我自己用这个。
  • 你有没有想过Kestrel combinators?该示例使用它进行日志记录,但您可以轻松地将其调整为缓存。

标签: scala scala-collections side-effects


【解决方案1】:

Future.andThen (scaladoc) 具有副作用并返回当前值的未来,以促进流畅的链接。

返回类型不是this.type

另请参阅duplicate questions 关于 Tap。

【讨论】:

  • +1 用于点击的引用。这似乎完全适合 OP 的需要
【解决方案2】:

您可以将 scalaz 用于副作用函数的“显式注释”。在 scalaz 7.0.6 中,它是 IO monad:http://eed3si9n.com/learning-scalaz/IO+Monad.html

在 scalaz 7.1 中已弃用。我会用 Task 做类似的事情

val readAndCache = Task.delay(read(id)).map(record => cacheRecord(record); record)
readAndCache.run // Run task for it's side effects

【讨论】:

  • 是否有任何关于此弃用的信息?它没有在源代码中这样注释或记录。
  • 现在找不到。邮件列表中讨论了 Task 应该替换 IO。但看起来它在 7.1 中并没有发生。它们在语义上都非常相似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多