Scala:将None用于除空选项之外的其他用途

Vil*_*tas 4 scala option implicit-conversion

根据文档,None对象旨在"代表不存在的值".据我所见,它主要用作空的Option.但是你认为将它用于其他目的是个好主意.例如,在我的库中,我希望有一个通用的"空"对象,可以为各种缺失值分配,我只是根据需要将"Empty"值隐式转换为我的类型:

// In library:
trait A {
  implicit def noneToT1(none: Option[Nothing]): T1 = defaultT1
  implicit def noneToT2(none: Option[Nothing]): T2 = defaultT2
  def f1: T1
  def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
  def f1 = None      
  def f2 = None      
}
Run Code Online (Sandbox Code Playgroud)

不使用(MIS)的原因之一None以这种方式是,用户会期望f1f2返回Option[T1]Option[T2]分别.他们没有.当然,我可以def f1: Option[T1],但在这种情况下,值实际上不是可选的,它们只能有一些默认的空值,或者一个实际值,我只想创建默认值"引擎盖下"并有一些统一的方式在整个图书馆中说"默认"或"空".所以问题是,我应该用它None来表达这种"默认"还是去寻找一些自定义类型?现在我正在使用自己的object Empty,但感觉有点多余.

编辑: 为了说明我的问题,我将立即添加我正在使用的代码:

// In library:
trait Empty
object Empty extends Empty

trait A {
  implicit def emptyToT1(none: Empty): T1 = defaultT1
  implicit def emptyToT2(none: Empty): T2 = defaultT2
  def f1: T1
  def f2: T2
}
// In the code that uses the library
class EmptyA extends A {
  def f1 = Empty
  def f2 = Empty
}
class HalfFullA extends A {
  def f1 = Empty
  def f2 = someValue2
}
class FullA extends A {
  def f1 = someValue1
  def f2 = someValue2
}
Run Code Online (Sandbox Code Playgroud)

我的问题很简单:使用scala None而不是my 是一个好主意Empty吗?

Itt*_*ayD 7

我只想使用类型类:

trait WithDefault[T] {
  def default: T
}

object WithDefault {
  // if T1 is an existing class
  implicit val t1Default = new WithDefault[T1] {def default = defaultT1}
}

//if T2 is your own class:
class T2 ...
object T2 {
  implicit val withDefault = new WithDefault[T2] {def default = defaultT2}
}
Run Code Online (Sandbox Code Playgroud)

然后方便的地方:

def default[T : WithDefault] = implicitly[WithDefault[T]].default
Run Code Online (Sandbox Code Playgroud)

并使用:

class EmptyA {
  def f1 = default[T1]
  def f2 = default[T2]
}
Run Code Online (Sandbox Code Playgroud)

更新:为了适应Vilius,可以试试这个:

def default = new WithDefault[Nothing]{def default = error("no default")}

implicit def toDefault[U, T](dummy: WithDefault[U])(implicit withDefault: WithDefault[T]): T = withDefault.default

class EmptyA {
  def f1: T1 = default
  def f2: T2 = default
}
Run Code Online (Sandbox Code Playgroud)

这有利于OP的原始尝试,因为每个新类都可以定义自己的默认值(以及WithDefault中的其他类),而不是将所有内容都放在特征中A.

但是,这不起作用.请参阅https://issues.scala-lang.org/browse/SI-2046

要解决这个问题:

trait A {
    def f1: T1
    def f2: T2

    implicit def toT1Default(dummy: WithDefault[Nothing]) = toDefault[T1](dummy)
    implicit def toT2Default(dummy: WithDefault[Nothing]) = toDefault[T2](dummy)
}

class EmptyA extends A {
   def f1 = default
   def f2 = default
}
Run Code Online (Sandbox Code Playgroud)