toma - ¿Podría/debería una adición implícita de T a la opción[T] agregarse/crearse en Scala?
presion arterial normal (6)
Eso se ve bien para mí, excepto que puede no funcionar para una T primitiva (que no puede ser nula). Supongo que un genérico no especializado siempre obtiene primitivos en caja, por lo que probablemente esté bien.
¿Es esta una oportunidad de hacer las cosas un poco más eficientes (para el prorammer): me parece un poco tedioso tener que envolver cosas en Some
, por ejemplo Some(5)
. ¿Qué tal algo así?
implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
Las pautas generales para las conversiones implícitas son las siguientes:
- Cuando necesite agregar miembros a un tipo (al estilo de "clases abiertas", también conocido como el patrón "pimp my library"),
AnyRef
a un nuevo tipo que amplíeAnyRef
y que solo defina los miembros que necesita. - Cuando necesita "corregir" una jerarquía de herencia. Por lo tanto, tiene algún tipo
A
que debería haber subclasificadoB
, pero no lo hizo por alguna razón. En ese caso, puede definir una conversión implícita deA
aB
Estos son los únicos casos en los que es apropiado definir una conversión implícita. Cualquier otra conversión se encuentra con problemas de seguridad y corrección de tipo a toda prisa.
Realmente no tiene sentido que T
extienda la Option[T]
, y obviamente el propósito de la conversión no es simplemente la adición de miembros. Por lo tanto, tal conversión sería desaconsejable.
Parece que esto podría ser confuso para otros desarrolladores, ya que leen su código.
En general, parece implicit
trabajos implicit
para ayudar a lanzar de un objeto a otro, para cortar el código de fundición confuso que puede desordenar el código, pero, si tengo alguna variable y de alguna manera se convierte en Some
entonces eso parecería ser molesto.
Es posible que desee colocar algún código que muestre que se está usando, para ver qué tan confuso sería.
Perderías algún tipo de seguridad y posiblemente causarías confusión. Por ejemplo:
val iThinkThisIsAList = 2
for (i <- iThinkThisIsAList) yield { i + 1 }
Yo (por cualquier razón) pensé que tenía una lista, y no fue captada por el compilador cuando la repetí porque se convirtió automáticamente en una Opción [Int].
Debo añadir que creo que esto es un gran implícito para haber importado explícitamente, probablemente no sea un valor predeterminado global.
También podría intentar sobrecargar el método:
def having(key:String) = having(key, None)
def having(key:String, default:String) = having(key, Some(default))
def having(key: String, default: Option[String]=Option.empty) : Create = {
keys += ( (key, default) )
this
}
Tenga en cuenta que podría utilizar el patrón explícito implícito que evitaría la confusión y mantendría el código al mismo tiempo.
Lo que quiero decir con implícito explícito es que en lugar de tener una conversión directa de T
a la Option[T]
podría tener una conversión a un objeto contenedor que proporciona los medios para hacer la conversión de T
a la Option[T]
.
class Optionable[T <: AnyRef](value: T) {
def toOption: Option[T] = if ( value == null ) None else Some(value)
}
implicit def anyRefToOptionable[T <: AnyRef](value: T) = new Optionable(value)
... Podría encontrar un nombre mejor que Optionable
, pero ahora puedes escribir código como:
val x: String = "foo"
x.toOption // Some("foo")
val y: String = null
x.toOption // None
Creo que esta forma es completamente transparente y ayuda a comprender el código escrito, eliminando todos los controles de nulos de una manera agradable.
Tenga en cuenta que T <: AnyRef
: solo debe hacer esta conversión implícita para los tipos que permiten valores null
, que por definición son tipos de referencia.