Domanda

Sto facendo un piccolo sistema di gestione problema Alzata per imparare sia Scala e di sollevamento.

Ho una visualizzazione che visualizza un singolo problema appartenenza a un progetto. Prima di associare dati al modello di vista, voglio verificare che ho tutti i dati richiesti, quindi voglio controllare in particolare che:

  • Un param progetto di ID è stato fornito
  • Esiste un progetto con il progetto di dotazione ID
  • Un param numero ID è stato fornito
  • Esiste un problema con la questione in dotazione ID

E questi devono essere valutati in ordine, quindi se dovessi scriverlo ora con la mia attuale comprensione della Scala, vorrei fare quanto segue:

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")
        }
}

Quindi mi chiedo se c'è un modo più semplice per eseguire questa? Penso che un per l'espressione potrebbe essere in grado di eseguire qualcosa di simile. Essere consapevoli che Project.findByID restituisce un Box [progetto].

È stato utile?

Soluzione

Scusate il così tardi allo spettacolo, ma come dice Daniel è possibile infatti utilizzare Box e di sollevamento? ~ Per fare qualcosa di simile. Ad esempio:

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")
    }
}

Che cosa? ~ Non fa altro che trasformare una scatola vuota in una Casella errore con il messaggio di errore dato String, ma non fa nulla per una completa (successo) Box. Quindi il valore di ritorno di findByID sarà completa se tutto riesce, o guasto (con il dato messaggio di errore) in caso contrario. Se si desidera che i fallimenti a catena, quindi utilizzare? ~! invece.

Altri suggerimenti

Non so ascensore, ma ci sono un paio di cose che ho visto nella sua attuazione. Uno di loro è metodi di guasto: ?~ e ?~!. Io non so esattamente come si potrebbe fare per il loro utilizzo, ma sembra di essere utile. Un altro è open_!, per generare eccezioni.

Ora, una mappa di supporto di sicurezza, flatMap, filtro e foreach, in modo che possa essere pienamente utilizzato all'interno di una di comprensione:

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

Questo non si otterrà i messaggi di errore. Per chi, sto cercando di indovinare i metodi che ho citato, o altri come ~>, potrebbe fornire la risposta.

Non so ascensore quindi non posso rispondere a qualsiasi domanda specifica-Lift. Ho, tuttavia, si avvicinò con un modo per risolvere uno del problema, che è come scrivere una sequenza di controllo-then-operare azioni senza ricorrere a pattern matching nidificato.

Il tipo di dati principale utilizzata qui è un'opzione, ma sono sicuro che sarà abbastanza facile da adattare alle proprie esigenze. Quello che vogliamo realizzare qui è quello di fare una sequenza di

  1. condizione di controllo
  2. continua in caso di successo
  3. terminare e restituire qualcosa altrimenti

Il codice fa una sorta di corto circuito volta incontra un Niente il valore restituito viene mantenuto quando la sequenza di azioni rendimenti. Per utilizzare, inizia con un'Opzione poi scrivere "ifSome" se l'opzione è un alcuni e "ifNone" se l'opzione è un Nessuno, continuerà fino a quando la sequenza è terminata. Se un incontro Nessuno è in qualsiasi punto della sequenza, l'opzione tornato da parametro di chiamata per nome di "isNone" viene mantenuta e restituito quando il "toOption" finale si chiama. Utilizzare "toOption" per ottenere indietro il risultato possibilità reale.

Controlla l'esempio in "principale" per alcuni casi d'uso. Buona fortuna!

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)
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top