Still have error “value copy is not a member of No

2019-07-31 10:43发布

问题:

I use scala 2.11.2. This is part of my function:

import scala.reflect.runtime.universe._
p => p.filter(p => typeOf[p.type] != typeOf[Nothing]).flatMap {
    case Some(profile) => {
        ...
        env.userService.save(profile.copy(passwordInfo = Some(hashed)),...) //<---------error here
    }
    case _ => ...
}

the compile error is:

PasswordReset.scala:120: value copy is not a member of Nothing
[error]                   env.userService.save(profile.copy(passwordI
nfo = Some(hashed)), SaveMode.PasswordChange);
[error]                                                ^

I think I use filter phase filter the Nothing type, but why it is still give me type Nothing error. I do not want to:

profile.getDefault().copy(...)

Because I really need to copy the profile instead of to copy the default value, if profile is Nothing just delete it. How to do it?

回答1:

Filter doesn't change types.

scala> def f[A](x: Option[A]) = x filter (_ != null)
f: [A](x: Option[A])Option[A]

Option[A] comes in, Option[A] goes out.

You're suggesting that the runtime check in your filter function should instruct the compiler to accept that your type param is not Nothing, but that's not how it works.

scala> f(None)
res2: Option[Nothing] = None

If Nothing is inferred, then Nothing is what you get.

You want to keep the compiler from inferring Nothing somewhere. Sometimes it's necessary to provide explicit type args to do that:

scala> f[String](None)
res3: Option[String] = None

scala> f[String](None) map (_.length)
res4: Option[Int] = None

compare to

scala> f(None) map (_.length)
<console>:9: error: value length is not a member of Nothing
              f(None) map (_.length)
                             ^

But it's also possible you could express your code differently.