简体   繁体   中英

scala lower bound type “with” another type?

Here is the code

class Result[A] {
    def map[B](f: (Result[A] => Result[B]), xResult: Result[A]) = {
      xResult match {
        case Success(x)    => Success(f(xResult))
        case Failure(errs) => Failure(errs)
      }
    }

    def apply[B](fResult: Result[A], xResult: Result[B]) = {
      (fResult, xResult) match {
        case (Success(f), Success(x))        => Success((f, x))
        case (Failure(errs), Success(a))     => Failure(errs)
        case (Success(a), Failure(errs))     => Failure(errs)
        case (Failure(errs), Failure(errs2)) => Failure(List(errs, errs2))
      }
    }
  }

  case class Success[A](a: A) extends Result[A] {}

  case class Failure[A](a: A) extends Result[A] {}

  def createCustomerId(id: Int) = {
    if (id > 0)
      Success(id)
    else
      Failure("CustomerId must be positive")
  }

Here are the questions

1) result from type inference from method createCustomer is like this

Product with Serializable with Result[_ >: Int with String] 

I dont have trouble with the "Product with Serializable" stuff, the thing im wondering is how to do something meaningfull with the result, and just out of curiosity how to initialize a type like that.

suppose i have another method as shown below

def createCustomer(customerId: Result[_ >: Int with String], email: Result[String]) = {
    how can i read/do something with "customerId" argument
  }

how to initialize a type like that

val x: Result[Int with String] = ???

notes:

  1. i know my Result class doesnt have any generic "getter"
  2. I know that perhaps things could be easier in method "createCustomerId" if when id > 0 i returned Success(id.ToString), but i really want to know whats going on with this lower type and how i could take advantage (if possible) in the future

The problem is that your type definition states that both Success and Failure take the same argument type. However, you actually want to put some other type of argument into Failure while still keeping covariance. Here is the simplest fix:

class Result[A] {

  def map[B](f: (Result[A] => Result[B]), xResult: Result[A]) = {
    xResult match {
      case Success(x) => Success(f(xResult))
      case Failure(errs) => Failure(errs)
    }
  }

  def apply[B](fResult: Result[A], xResult: Result[B]) = {
    (fResult, xResult) match {
      case (Success(f), Success(x)) => Success((f, x))
      case (Failure(errs), Success(a)) => Failure(errs)
      case (Success(a), Failure(errs)) => Failure(errs)
      case (Failure(errs), Failure(errs2)) => Failure(List(errs, errs2))
    }
  }
}

case class Success[A](a: A) extends Result[A] {}

case class Failure[A, B](a: B) extends Result[A] {}

object TestResult extends App {

  def createCustomerId(id: Int): Result[Int] = {
    if (id > 0)
      Success(id)
    else
      Failure("CustomerId must be positive")
  }

  println(createCustomerId(0))
  println(createCustomerId(1))
}

prints:

Failure(CustomerId must be positive)
Success(1)

If you don't annotate return type for createCustomerId with Result[Int] compiler will infer Result[_ <: Int] with Product with Serializable which is probably not ideal but not too bad.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM