2012-03-15 15 views
23

Ho un metodo come questo:Scala parametri predefiniti e nulli

def aMethod(param: String = "asdf") = { 
    ... 
} 

Se il metodo è chiamato come segue, quindi param viene dato il valore di default "asdf":

aMethod() ... 

Ma cosa desidero, è che se il metodo è chiamato con null, allora il valore di default dovrebbe essere applicato anche:

aMethod(null) //inside the method, I can use `param` and it has the value "asdf". 

Qual'è il modo migliore per farlo in Scala? Posso pensare alla corrispondenza del modello o una semplice dichiarazione if.

risposta

46

pattern matching

def aMethod(param: String = null) { 
    val paramOrDefault = param match { 
     case null => "asdf" 
     case s => s 
    } 
} 

Opzione (implicitamente)

def aMethod(param: String = null) { 
    val paramOrDefault = Option(param).getOrElse("asdf") 
} 

Opzione (esplicitamente)

def aMethod(param: Option[String] = None) { 
    val paramOrDefault = param getOrElse "asdf" 
} 

L'ultimo approccio è in realtà il più idiomatica e leggibile una volta che si ottiene l'uso di esso.

+1

C'è un modo per convertire implicitamente in un'opzione? Certo, potrei scrivere la mia def, ma è già presente nella API? –

+4

@JohnSmith: vuoi dire qualcosa come: 'implicit def obj2Option [T] (t: T) = Option (t)'? Penso che questo sia un po 'troppo fragile/pericoloso per far parte delle conversioni implicite standard, non ne conosco. –

+0

@TomaszNurkiewicz si prega di vedere la mia risposta, poiché questa soluzione, ad un esame più approfondito, avrà un impatto negativo sugli strumenti di sviluppo di Scala e avrà il potenziale per rompere il codice ogni volta che è coinvolta l'ereditarietà. –

5
def aMethod(param: String = null) = { 
    val p = 
    if(param == null) 
     "asdf" 
    else 
     param 

    println(p) 
} 

Ma la domanda deve essere posta: perché consentire null? Option sarebbe possibile nel tuo caso? Per questo si potrebbe fare:

def aMethod(param: Option[String]) = { 
    val p = param.getOrElse("asdf")  
    println(p) 
} 

Questo rende chiaro che il metodo prevede la possibilità di un argomento "nullo".

5

Se il metodo ha solo uno o due di default i parametri che possono essere impostati per null considerare questo modello:

// please note that you must specify function return type 
def aMethod (x:String = "asdf"):String = if (x==null) aMethod() else { 
    // aMethod body ... 
    x 
} 

ci sono alcuni vantaggi:

  • La definizione metodo indica chiaramente di default del parametro valore.
  • Il valore predefinito corretto può essere selezionato dagli strumenti Scala, incluso ScalaDoc.
  • Non è necessario definire un valore aggiuntivo per sostituire il parametro originale all'interno del corpo del metodo - meno spazio per errori, più facile da ragionare.
  • Il modello è abbastanza conciso.

Inoltre, si consideri il seguente scenario:

trait ATrait { 
    def aMethod (x:String = "trait's default value for x"):String 
} 

class AClass extends ATrait { 
    .... 
} 

Chiaramente, qui dobbiamo estendere il tratto, preservando il valore predefinito originale.Uno dei motivi che coinvolgono inizialmente l'impostazione del parametro null seguito da un valore predefinito di controllo e reale si romperà il contratto stabilito dal tratto:

class AClass extends ATrait { 
    // wrong, breaks the expected contract 
    def aMethod(x: String = null):String = { 
     val xVal = if (x == null) "asdf" else x 
     ... 
    } 
} 

Infatti in questo scenario l'unico modo per preservare il valore originale ATrait sarà:

class AClass extends ATrait { 
    override def aMethod (x:String):String = if (x==null) aMethod() else { 
    ... // x contains default value defined within ATrait 
    } 
} 

Tuttavia, nello scenario in cui ci sono più di uno o due parametri predefiniti che possono essere impostati per null il modello comincia a diventare piuttosto disordinato:

// two parameters 
def aMethod (x:String = "Hello",y:String = "World"):String = 
    if (x==null) aMethod(y=y) else 
    if (y==null) aMethod(x=x) else { 
    // aMethod body ... 
    x + " " + y 
} 

// three parameters 
def aMethod (x:String = "Hello",y:String = " ",z:String = "World"):String = 
    if (x==null) aMethod(y=y,z=z) else 
    if (y==null) aMethod(x=x,z=z) else 
    if (z==null) aMethod(x=x,y=y) else { 
    // aMethod body ... 
    x + y + z 
} 

Ancora quando si esegue l'override di un contratto esistente, questo potrebbe essere l'unico modo per rispettare i valori predefiniti originali.

+0

Mi piace molto il tuo approccio (e la giustificazione); Vorrei poter dare più punti; poiché penso che dovrebbe essere la risposta. Grazie. – Neil

Problemi correlati