2012-03-15 23 views
23

que tienen un método como este:parámetros por defecto Scala y nula

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

Si el método se denomina de la siguiente manera, a continuación, parámetro se le da el valor por defecto "asdf":

aMethod() ... 

Pero lo me gustaría, es que si el método se llama con null, entonces el valor por defecto podría también ser aplicado:

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

¿Cuál es la mejor manera de hacer esto en Scala? Puedo pensar en la coincidencia de patrones o una simple declaración if.

Respuesta

46

coincidencia de patrones

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

Opción (implícitamente)

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

Opción (explícitamente)

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

El último enfoque es en realidad el más idiomática y fácil de leer una vez que el uso de eso.

+1

¿Hay alguna manera de convertir implícitamente a una opción? Claro que podría escribir mi propia definición, ¿pero ya hay una en la API? –

+4

@JohnSmith: quieres decir algo como: 'implicit def obj2Option [T] (t: T) = Option (t)'? Creo que esto es demasiado frágil/peligroso para ser parte de las conversiones implícitas estándar, no sé de ninguna. –

+0

@TomaszNurkiewicz por favor vea mi respuesta, ya que esta solución, en un examen más detallado, tendrá un impacto negativo en las herramientas de desarrollo de Scala y tendrá el potencial de romper el código cuando se trate de la herencia. –

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

    println(p) 
} 

Pero la pregunta debe hacerse: ¿por qué permitir null? ¿Sería posible Option en su caso? Para este propósito puede hacer:

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

Esto deja claro que el método espera la posibilidad de un argumento "nulo".

5

Si el método tiene sólo uno o dos por defecto los parámetros que se pueden ajustar a null considerar este patrón:

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

hay algunas ventajas:

  • La definición del método indica claramente predeterminado del parámetro valor.
  • El valor predeterminado correcto puede ser elegido por las herramientas de Scala, incluido ScalaDoc.
  • No hay necesidad de definir un valor adicional para sustituir el parámetro original dentro del cuerpo del método, hay menos espacio para errores, es más fácil razonar.
  • El patrón es bastante conciso.

Además, considere la situación siguiente:

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

class AClass extends ATrait { 
    .... 
} 

Claramente, aquí tenemos que extender el rasgo, al tiempo que preserva el valor predeterminado original.Cualquiera de los patrones que supongan poner inicialmente el parámetro a null seguido de un valor por defecto de verificación y la real se romperá el contrato establecido por el rasgo:

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

De hecho, en este escenario, la única manera de preservar el valor original de ATrait serán los siguientes:

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

Sin embargo, en el escenario cuando hay más de uno o dos parámetros por defecto que se pueden ajustar a null el patrón empieza a ser bastante desordenado:

// 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 
} 

Sin embargo, al anular un contrato existente, esta podría ser la única forma de respetar los valores predeterminados originales.

+0

Me gusta mucho su enfoque (y justificación); Ojalá pudiera darle más puntos; ya que creo que debería ser la respuesta. Gracias. – Neil

Cuestiones relacionadas