introduccion - ¿Por qué las personas definen clase, rasgo, objeto dentro de otro objeto en Scala?
scala introduccion (4)
Ok, voy a explicar por qué hago esta pregunta. Comienzo a leer el código fuente de Lift 2.2 en estos días. Es bueno si leíste el código fuente de Lift anteriormente.
En Lift, encontré que, la clase interna y el rasgo interno son muy utilizados.
El Menu objeto tiene 2 rasgos internos y 4 clases internas. El objeto Loc tiene 18 clases internas, 5 rasgos internos, 7 objetos internos.
Hay toneladas de códigos que escriben así. Quiero saber por qué el autor escribe así.
- ¿Es porque es el gusto personal del autor o un uso poderoso del lenguaje?
- ¿Hay alguna compensación para este tipo de uso?
A veces es necesario colocar clases, rasgos y objetos en un objeto cuando desee usar variables de tipo abstracto, ver, por ejemplo, http://programming-scala.labs.oreilly.com/ch12.html#_parameterized_types_vs_abstract_types
Antes de 2.8, tenías que elegir entre paquetes y objetos. El problema con los paquetes es que no pueden contener métodos o valores por sí mismos. Así que tienes que poner todos esos dentro de otro objeto, lo que puede volverse incómodo. Observar:
object Encrypt {
private val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = encryptInt(ii.next)
}
}
Ahora puede import Encrypt._
y obtener acceso al método encryptInt
, así como a la clase EncryptIterator
. ¡Práctico!
A diferencia de,
package encrypt {
object Encrypt {
private[encrypt] val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
}
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = Encrypt.encryptInt(ii.next)
}
}
No es una gran diferencia, pero hace que el usuario importe tanto encrypt._
como encrypt.Encrypt._
o tenga que seguir escribiendo Encrypt.encryptInt
una y otra vez. ¿Por qué no usar un objeto en su lugar, como en el primer patrón? (Realmente no hay una penalización de rendimiento, ya que las clases anidadas no son en realidad clases internas de Java bajo el capó; solo son clases regulares, por lo que sabe la JVM, pero con nombres sofisticados que te dicen que están anidadas).
En 2.8, puedes tener tu pastel y comértelo también: llama a lo que es un objeto de paquete, y el compilador reescribirá el código para que se vea como el segundo ejemplo debajo del capó (excepto que el objeto Encrypt
realidad se llama package
internamente ), pero se comporta como el primer ejemplo en términos de espacio de nombres: los valores y las definiciones están justo ahí sin necesidad de una importación adicional.
Por lo tanto, los proyectos que se iniciaron antes de la versión 2.8 a menudo usan objetos para encerrar muchas cosas como si fueran un paquete. Post-2.8, una de las principales motivaciones ha sido eliminada. (Pero para ser claro, usar un objeto todavía no duele; es más que es conceptualmente engañoso que tener un impacto negativo en el rendimiento o lo que sea).
(PD: ¡Por favor, no intentes cifrar nada de esa manera, excepto como un ejemplo o una broma!)
Pueden ser ambas cosas. Entre otras cosas, una instancia de una clase / rasgo interno tiene acceso a las variables de su padre. Las clases internas tienen que crearse con una instancia principal, que es una instancia del tipo externo.
En otros casos, probablemente sea solo una forma de agrupar cosas estrechamente relacionadas, como en el ejemplo de object
. Tenga en cuenta que el rasgo LocParam
está sellado, lo que significa que todas las subclases deben estar en la misma unidad / archivo de compilación.
Sblundy tiene una respuesta decente. Una cosa para agregar es que solo con Scala 2.8 tiene objetos de paquete que le permiten agrupar cosas similares en un espacio de nombre de paquete sin hacer un objeto completamente separado. Por esa razón, actualizaré mi propuesta de Lift Modules para usar un objeto de paquete en lugar de un objeto simple.