另一种创建 Anyval Option 的尝试
Yet another attempt of creating Anyval Option
我正在尝试实现一个不为包装器消耗额外内存的选项。
我创建了一个 class。 Null代表None,非null值代表Some.
class Maybe[+T](private val nullable: T) extends AnyVal {
@inline final def isDefined: Boolean = {
println("isDefined called")
val res = nullable != null
println(s"result = $res")
res
}
@inline final def get: T = if (isDefined) nullable else throw new NoSuchElementException
@inline final def getOrElse[B >: T](default: => B): B = if (isDefined) this.get else default
@inline final def map[B](f: T => B) : Maybe[B] = if (isDefined) Maybe.some(f(this.get)) else Maybe.none
@inline final def flatMap[B](f: T => Maybe[B]): Maybe[B] = if (!isDefined) Maybe.none else f(get)
def toOption : Option[T] = if (isDefined) Some(get) else None
}
object Maybe {
def some[T](value:T) : Maybe[T] = new Maybe(value)
final val none : Maybe[Nothing] = {
println("start initializing none")
val v = new Maybe(null)
println("1")
val res = v.asInstanceOf[Maybe[Nothing]]
println("2")
res
}
}
object MaybeTest extends App {
println("try to create Maybe.none")
val myNone = Maybe.none
println("Initialized")
println(myNone.isDefined)
println("Accessed")
}
但是当我尝试 运行 它时,我得到了一个 NPE:
try to create Maybe.none
start initializing none
1
2
Initialized
Exception in thread "main" java.lang.NullPointerException at
com.MaybeTest$.delayedEndpoint$com$MaybeTest(Maybe.scala:34)
at
com.MaybeTest$delayedInit$body.apply(Maybe.scala:30)
at scala.Function0$class.apply$mcV$sp(Function0.scala:34) at
scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main.apply(App.scala:76) at
scala.App$$anonfun$main.apply(App.scala:76) at
scala.collection.immutable.List.foreach(List.scala:392) at
scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
at scala.App$class.main(App.scala:76) at
com.MaybeTest$.main(Maybe.scala:30) at
com.MaybeTest.main(Maybe.scala)
如果我删除 'extends AnyVal' 一切正常。
谁能解释这种行为?
@Jasper-M 的评论解释了为什么您的解决方案不起作用,但这很接近:
class Maybe[+T] private (private val nullable: Object) extends AnyVal {
@inline private final def get0 = nullable.asInstanceOf[T]
@inline final def isDefined: Boolean = nullable != null
@inline final def get: T = if (isDefined) get0 else throw new NoSuchElementException
@inline final def getOrElse[B >: T](default: => B): B = if (isDefined) get0 else default
@inline final def map[B](f: T => B) : Maybe[B] = if (isDefined) Maybe.some(f(get0)) else Maybe.none
@inline final def flatMap[B](f: T => Maybe[B]): Maybe[B] = if (!isDefined) Maybe.none else f(get0)
@inline final def toOption: Option[T] = if (isDefined) Some(get0) else None
}
object Maybe {
def some[A](value: A) : Maybe[A] = {
val value1 = value.asInstanceOf[Object]
assert(value1 != null)
new Maybe[A](value1)
}
private val _none = new Maybe[Null](null)
def none[A]: Maybe[A] = _none.asInstanceOf[Maybe[A]]
def apply[A](value: A) = new Maybe[A](value.asInstanceOf[Object])
}
但它并不是真正的 "an Option
which doesn't consume extra memory for a wrapper":它只是用另一个名字调用 null
。例如。 Option[Option[A]]
按预期工作,但 Maybe[Maybe[A]]
没有(编译器不会告诉你!)。
我正在尝试实现一个不为包装器消耗额外内存的选项。 我创建了一个 class。 Null代表None,非null值代表Some.
class Maybe[+T](private val nullable: T) extends AnyVal {
@inline final def isDefined: Boolean = {
println("isDefined called")
val res = nullable != null
println(s"result = $res")
res
}
@inline final def get: T = if (isDefined) nullable else throw new NoSuchElementException
@inline final def getOrElse[B >: T](default: => B): B = if (isDefined) this.get else default
@inline final def map[B](f: T => B) : Maybe[B] = if (isDefined) Maybe.some(f(this.get)) else Maybe.none
@inline final def flatMap[B](f: T => Maybe[B]): Maybe[B] = if (!isDefined) Maybe.none else f(get)
def toOption : Option[T] = if (isDefined) Some(get) else None
}
object Maybe {
def some[T](value:T) : Maybe[T] = new Maybe(value)
final val none : Maybe[Nothing] = {
println("start initializing none")
val v = new Maybe(null)
println("1")
val res = v.asInstanceOf[Maybe[Nothing]]
println("2")
res
}
}
object MaybeTest extends App {
println("try to create Maybe.none")
val myNone = Maybe.none
println("Initialized")
println(myNone.isDefined)
println("Accessed")
}
但是当我尝试 运行 它时,我得到了一个 NPE:
try to create Maybe.none
start initializing none
1
2
Initialized
Exception in thread "main" java.lang.NullPointerException at com.MaybeTest$.delayedEndpoint$com$MaybeTest(Maybe.scala:34) at com.MaybeTest$delayedInit$body.apply(Maybe.scala:30) at scala.Function0$class.apply$mcV$sp(Function0.scala:34) at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12) at scala.App$$anonfun$main.apply(App.scala:76) at scala.App$$anonfun$main.apply(App.scala:76) at scala.collection.immutable.List.foreach(List.scala:392) at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35) at scala.App$class.main(App.scala:76) at com.MaybeTest$.main(Maybe.scala:30) at com.MaybeTest.main(Maybe.scala)
如果我删除 'extends AnyVal' 一切正常。 谁能解释这种行为?
@Jasper-M 的评论解释了为什么您的解决方案不起作用,但这很接近:
class Maybe[+T] private (private val nullable: Object) extends AnyVal {
@inline private final def get0 = nullable.asInstanceOf[T]
@inline final def isDefined: Boolean = nullable != null
@inline final def get: T = if (isDefined) get0 else throw new NoSuchElementException
@inline final def getOrElse[B >: T](default: => B): B = if (isDefined) get0 else default
@inline final def map[B](f: T => B) : Maybe[B] = if (isDefined) Maybe.some(f(get0)) else Maybe.none
@inline final def flatMap[B](f: T => Maybe[B]): Maybe[B] = if (!isDefined) Maybe.none else f(get0)
@inline final def toOption: Option[T] = if (isDefined) Some(get0) else None
}
object Maybe {
def some[A](value: A) : Maybe[A] = {
val value1 = value.asInstanceOf[Object]
assert(value1 != null)
new Maybe[A](value1)
}
private val _none = new Maybe[Null](null)
def none[A]: Maybe[A] = _none.asInstanceOf[Maybe[A]]
def apply[A](value: A) = new Maybe[A](value.asInstanceOf[Object])
}
但它并不是真正的 "an Option
which doesn't consume extra memory for a wrapper":它只是用另一个名字调用 null
。例如。 Option[Option[A]]
按预期工作,但 Maybe[Maybe[A]]
没有(编译器不会告诉你!)。