ScalaCats入门


介绍 本文是关于Scala Cats的。它是一个库,为使用Scala编程语言的功能编程提供了抽象。这个名字是单词类别的一个好玩的缩写。

Cats是用于函数式编程的轻量级,模块化和可扩展的库。

Cats包含各种功能编程工具,并允许开发人员选择所需的工具。这些工具中的大多数以类型类的形式提供,我们可以将其应用于现有的Scala类型。

什么是类型类?

类型类是源自Haskell的编程模式。它们使我们能够使用新功能扩展现有库,而无需使用传统继承,也无需更改原始库源代码。

类型类模式有三个重要的组成部分:类型类本身,特定类型的实例以及使用类型类的方法。

什么是类型类?

类型类是表示我们要实现的某些功能的接口或API。在Scala中,类型类由具有至少一个类型参数的特征表示。

例如,我们可以表示通用的“序列化为JSON”行为,如下所示:

// Define a very simple JSON AST
sealed trait Json
final case class JsObject(get: Map[String, Json]) extends Json
final case class JsString(get: String) extends Json
final case class JsNumber(get: Double) extends Json
final case object JsNull extends Json
// The "serialize to JSON" behaviour is encoded in this trait
trait JsonWriter[A] {
  def write(value: A): Json
}

什么是类型类实例?

类型类的实例为我们关心的特定类型提供了类型类的实现,其中可以包括Scala标准库中的类型和域模型中的类型。

在Scala中,我们通过创建类型类的具体实现并使用隐式关键字对其进行标记来定义实例:

final case class Person(name: String, email: String)
object JsonWriterInstances {
  implicit val stringWriter: JsonWriter[String] = new JsonWriter[String] {
    def write(value: String): Json = JsString(value)
  }
  implicit val personWriter: JsonWriter[Person] = new JsonWriter[Person] {
    def write(value: Person): Json =
      JsObject(Map(
        "name" -> JsString(value.name),
        "email" -> JsString(value.email)
      ))
  }
}

如何使用类型类?

使用类型类是需要类型类实例才能工作的任何功能。在Scala中,这意味着将类型类的实例作为隐式参数接受的任何方法。

Cats提供的实用程序使类型类更易于使用,有时您会在其他库中看到这些模式。

有两种方法可以执行此操作:接口对象和接口语法。

什么是接口对象?

创建使用类型类的接口的最简单方法是将方法放在单例对象中:

object Json {
  def toJson[A](value: A)(implicit w: JsonWriter[A]): Json = w.write(value)
}

要使用此对象,我们将导入我们关心的任何类型类实例,并调用相关方法:

import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))

编译器发现我们已经调用了toJson方法,而没有提供隐式参数。它尝试通过搜索相关类型的类型类实例并将其插入到调用站点中来解决此问题:

Json.toJson(Person("Dave", "dave@example.com"))(personWriter)

什么是接口语法?

我们也可以使用扩展方法来通过接口方法扩展现有类型。对于类型类,Cat将此称为“语法”:

object JsonSyntax {
  implicit class JsonWriterOps[A](value: A) {
    def toJson(implicit w: JsonWriter[A]): Json = w.write(value)
  }
}

我们通过将接口语法与实例一起导入所需类型的实例来使用接口语法:

import JsonWriterInstances._
import JsonSyntax._
Person("Dave", "dave@example.com").toJson

再次,编译器搜索隐式参数的候选者并为我们填写它们:

Person("Dave", "dave@example.com").toJson(personWriter)

在Scala中使用类型类意味着使用隐式值和隐式参数。为了有效地做到这一点,我们需要了解一些规则。

Scala中标记为隐式的所有定义都必须放置在对象或特征内,而不是顶层。

在上面的示例中,我们将类型类实例打包在一个名为JsonWriterInstances的对象中。我们同样可以将它们放在JsonWriter的伴随对象中。在Scala中,将实例放置在类型类的伴随对象中具有特殊的意义,因为它会发挥作用,称为隐式作用域。

什么是隐式范围?

正如我们在上面看到的,编译器按类型搜索候选类型类实例。

例如,在下面的表达式中,它将查找JsonWriter [String]类型的实例:

JSON。toJson(“一个字符串!”)

编译器搜索候选实例的位置称为隐式作用域。隐式作用域适用于调用站点,这是我们使用隐式参数调用方法的地方。

概括

在本文中,我们首先了解了类型类。

我们看到了组成类型类的组件:

  • A trait, which is the type class. Type class instances, which are implicit values.Type class usage, which uses implicit parameters.


原文链接:http://codingdict.com