Question

Je fais un petit système de gestion des problèmes dans Lift pour apprendre à la fois Scala et un ascenseur.

J'ai une vue qui affiche une seule question appartenant à un projet. Avant que je lier des données au modèle de vue, je veux vérifier que j'ai toutes les données nécessaires, donc je veux vérifier précisément que:

  • Un projet ID a été fourni param
  • Un projet existe avec le projet fourni ID
  • Un numéro ID a été fourni param
  • Il existe un problème avec le numéro fourni ID

Et ceux-ci doivent être évalués afin, donc si je devais écrire maintenant avec ma compréhension actuelle de la Scala, je fais ce qui suit:

class Project {
    def findByID(xhtml:NodeSeq): NodeSeq = 
        param("projectID") match {
            case Full(projectID) =>
                Project.findByID(projectID) match {
                    case Full(projectID) =>
                        param("issueID") match {
                            ....
                        }
                    case _ => Text("Project does not exist")
                }
            case _ => Text("projectIDNotSupplied")
        }
}

Je me demande donc s'il y a un moyen plus facile à réaliser cela? Je pense que l'expression est peut-être en mesure d'effectuer quelque chose de similaire. Sachez que Project.findByID retourne une boîte [Projet].

Était-ce utile?

La solution

Désolé, je suis en retard pour le spectacle, mais comme Daniel dit que vous pouvez en effet utiliser la boîte de levage et? ~ Faire quelque chose comme ça. Par exemple:

import net.liftweb.util.Box
import net.liftweb.util.Box._

class Project {
  def findByID(xhtml:NodeSeq): NodeSeq = 
    (for {
      projectID <- param("projectID") ?~ "projectIDNotSupplied"
      project <- Project.findById(projectID) ?~ "Project does not exist"
      issueID <- param("issueID") ?~ "issueIDNotSupplied"
      ...
    } yield {
      ...
    }) match {
      case Full(n) => n
      case Failure(msg, _, _) => Text(msg)
      case _ => Text("fail")
    }
}

Qu'est-ce? ~ Fait à son tour est une boîte vide dans une zone de défaut avec le message d'erreur de chaîne donnée, mais ne fait rien à un complet (succès) Box. Ainsi, la valeur de retour de findById sera pleine si tout réussit ou non (avec le message d'erreur donné) autrement. Si vous voulez que les échecs à la chaîne, utilisez alors? ~! à la place.

Autres conseils

Je ne sais pas d'ascenseur, mais il y a deux ou trois choses que je l'ai vu dans sa mise en œuvre. L'un d'eux est les méthodes d'échec: ?~ et ?~!. Je ne sais pas exactement comment on pourrait s'y prendre pour les utiliser, mais il semble être utile. Une autre est open_!, de lever des exceptions.

, une carte de support de boîte, flatMap, filtre et foreach, il peut donc être pleinement utilisé à l'intérieur d'une compréhension pour:

for(projectID <- param("projectID");
    if Project.findByID(projectID).isDefined;
    issueID <- param("issueID");
    if Issue.findByID(issueID).isDefined)
yield ...

Vous n'obtiendrez pas les messages d'erreur. Pour ceux-ci, je devine les méthodes que je parlais, ou d'autres comme ~>, peut-être fournir la réponse.

Je ne sais pas d'ascenseur, donc je ne peux pas répondre à des questions spécifiques à l'ascenseur. Je, cependant, est venu avec une façon de résoudre un problème qui est votre façon d'écrire une séquence de contrôle-puis-Operate actions sans avoir recours à des filtrages emboîtés.

Le principal type de données utilisé ici est l'option, mais je suis sûr que ce sera assez facile d'adapter à vos besoins. Ce que nous voulons accomplir ici est de faire une séquence de

  1. Vérifier l'état
  2. continuer en cas de succès
  3. et mettre fin à retourner quelque chose autrement

Le code fait une sorte de court-circuit, une fois qu'il rencontre un Aucun si la valeur de retour est conservé lorsque la séquence des rendements d'actions. Pour l'utiliser, commence par une option puis écrire « ifSome » si l'option est une partie et « ifNone » si l'option est None, continuez jusqu'à ce que la séquence soit terminée. Si une rencontre est Aucun à tout moment dans la séquence, l'option retour de paramètre appel par nom de « isNone » est conservé et renvoyé lorsque le « toOption » finale est appelée. Utilisez « toOption » pour récupérer le résultat réel de l'option.

Consultez l'exemple dans « principale » pour certains cas d'utilisation. Bonne chance!

object Options {

  class RichOption[A](a: Option[A]) {

    def ifSome[B](f: A => Option[B]): RichOption[B] = a match {
      case Some(x) => new RichOption(f(x))
      case None => this.asInstanceOf[RichOption[B]]
    }

    def ifNone[B](f: => Option[B]): RichOption[B] = a match {
      case Some(_) => this.asInstanceOf[RichOption[B]]
      case None => new RichNone(f)
    }

    def toOption[A] = a
  }

  class RichNone[A](a: Option[A]) extends RichOption[A](a) {

    override def ifSome[B](f: A => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]]

    override def ifNone[B](f: => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]]
  }

  implicit def option2RichOption[A](a: Option[A]): RichOption[A] = new RichOption(a)

  def main(args: Array[String]) {
    println(Some("hello") ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO)
    println(Some("hello") ifNone(Some("empty")) toOption) // prints Some(hello)
    println(Some("hello") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(HELLO)
    println(Some("hello") ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO)
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) toOption) // prints None
    println((None: Option[String]) ifNone(Some("empty")) toOption) // prints Some(empty)
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(empty)
    println((None: Option[String]) ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(empty)
    println(Some("hello world") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(11)
    println(Some("hello world") ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world)
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(empty)
    println((None: Option[String]) ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world)
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top