type tipos sharp datos anonimos c# scala tuples

tipos - list anonymous type c#



¿Hay una manera de tener tuplas con campos con nombre en Scala, similar a las clases anónimas en C#? (5)

Como sugiere Juh_, extender una clase de caso debería hacer lo que quieras:

scala> case class E(id: Int, name: String) defined class E scala> val e = new E(5, "Prashant") e: E = E(5,Prashant) scala> e.name res3: String = Prashant

Las clases de casos proporcionan un método igual y también extienden el rasgo del Product , que es el mismo rasgo que las tuplas de Scala extienden. Quizás en el futuro también extiendan los rasgos de ProductN .

Si usa clases anónimas como se sugiere en algunas otras respuestas, ¡no terminará con tuplas reales! Por ejemplo, no obtienes el método equals:

scala> val x = new { val count = 5 } x: AnyRef{val count: Int} = $anon$1@29ca901e scala> val y = new { val count = 5 } y: AnyRef{val count: Int} = $anon$1@1dfe2924 scala> x == y res4: Boolean = false

A partir de Scala 2.11, la ampliación de Tuple2 funciona, pero está en desuso porque no se supone que se extiendan las clases de casos.

También podría extender el rasgo Product2 , pero eso no proporciona implementaciones de ningún método, por lo que tendría que escribir todos los métodos usted mismo.

Probablemente también podría usar un HList de HList , que le daría muchas funciones extravagantes al costo de agregar una dependencia externa.

También probé la biblioteca jaqen de Twitter, pero eso no se jaqen en Scala 2.11.

Actualmente estoy usando Scala 2.11, por lo que no puedo garantizar que este consejo se aplique a otras versiones de Scala.

Consulte: ¿Puedo especificar un nombre significativo para una clase anónima en C #?

En C # puedes escribir:

var e = new { ID = 5, Name= "Prashant" }; assertEquals( 5, e.ID )

Pero en Scala termino escribiendo:

var e = (5, "Prashant") assertEquals( 5, e._1 )

Scala mantiene la seguridad de tipos mediante el uso de genéricos (al igual que C #), pero pierde la legibilidad del nombre de cada campo, por ejemplo, uso "_1" en lugar de "ID".

¿Hay algo como esto en Scala?



Simplemente haría una clase de caso:

object Yo{ case class E(id: Int, name: String) def main(){ val e = E(5,"Prashant") println("name="+e.name+", id="+e.id) } }

No estoy seguro si es tan eficiente como la respuesta de Daniel, pero espero que sea lo mismo (agradecería los comentarios al respecto). En cualquier caso, lo encuentro más legible, utilizando solo una línea adicional que se comparte si tiene más de una instancia si E También puede agregar un método a la clase de caso, como:

case class E(id: Int, name: String){ def hasId(id: Int) = this.id==id } val e = E(5,"Prashant") assert(e hasId 5)


También puede nombrar las partes de la tupla que está asignando, como en:

val (ID, Name) = (5, "Prashant") assertEquals( 5, ID )

También puedes usar esto como:

val (ID, Name, Age) = functionThatReturnsATuple3 println("ID: " + ID + ", age: " + Age)

Cuando leí por primera vez sobre la sintaxis de _x , pensé que era genial y la usé mucho. Básicamente, desde que dejé de usar el código que escribí hace dos meses, dejé de usarlo. Tengo que perder mucho tiempo intentando averiguar cuáles son los tipos de _1 , _2 , etc. Supongo que, en retrospectiva, es obvio que la id es mucho más legible que pair._1 .

Esto también se puede utilizar dentro de funciones como map , filter , etc., como:

val list: List[ (Int, String, Double) ] = ... list map { case (id, name, time) => ... } list filter { case (_, name, _) => name == "X" }

Tenga en cuenta que en el filter puede usar _ s para elementos que no va a usar en el cuerpo de la función. Esto puede ser útil cuando se hojea código como ese para establecer qué partes de las estructuras se están utilizando y cómo se construyen los valores.


object T { def main(args: Array[String]) { val e = new { var id = 5; var name = "Prashant" } assert(e.id == 5) } }

Ok, dejemos las cosas claras. Esto utiliza la reflexión en Scala 2.7 y Scala 2.8, porque el tipo de e es, en este caso, un tipo estructural , que Scala maneja a través de la reflexión. Aquí está el código generado, en el momento de la limpieza ( scalac -Xprint:cleanup ):

package <empty> { final class T extends java.lang.Object with ScalaObject { private <synthetic> <static> var reflMethod$Cache1: java.lang.reflect.Method = null; private <synthetic> <static> var reflClass$Cache1: java.lang.Class = null; <synthetic> <static> def reflMethod$Method1(x$1: java.lang.Class): java.lang.reflect.Method = { if (T.this.reflMethod$Cache1.eq(null).||(T.this.reflClass$Cache1.ne(x$1))) { T.this.reflMethod$Cache1 = x$1.getMethod("id", Array[java.lang.Class]{}); T.this.reflClass$Cache1 = x$1; () }; T.this.reflMethod$Cache1 }; @remote def $tag(): Int = scala.ScalaObject$class.$tag(T.this); def main(args: Array[java.lang.String]): Unit = { val e: java.lang.Object = { new T$$anon$1() }; scala.this.Predef.assert(scala.Int.unbox({ var exceptionResult1: java.lang.Object = _; try { exceptionResult1 = T.reflMethod$Method1(e.getClass()).invoke(e, Array[java.lang.Object]{}) } catch { case ($1$ @ (_: java.lang.reflect.InvocationTargetException)) => { exceptionResult1 = throw $1$.getCause() } }; exceptionResult1 }.$asInstanceOf[java.lang.Integer]()).==(5)) }; def this(): object T = { T.super.this(); () } }; final class T$$anon$1 extends java.lang.Object { private[this] var id: Int = _; <accessor> def id(): Int = T$$anon$1.this.id; <accessor> def id_=(x$1: Int): Unit = T$$anon$1.this.id = x$1; private[this] var name: java.lang.String = _; <accessor> def name(): java.lang.String = T$$anon$1.this.name; <accessor> def name_=(x$1: java.lang.String): Unit = T$$anon$1.this.name = x$1; def this(): T$$anon$1 = { T$$anon$1.this.id = 5; T$$anon$1.this.name = "Prashant"; T$$anon$1.super.this(); () } } }

Hay algo de almacenamiento en caché en marcha, pero si alterno entre id y name ya se invalidaría el caché. Scala 2.8 también hace reflexión, y también almacena en caché, pero utiliza una técnica de almacenamiento en caché más eficiente, que debería proporcionar un mejor rendimiento general. Para referencia, aquí está la limpieza de Scala 2.8:

package <empty> { final class T extends java.lang.Object with ScalaObject { final private <synthetic> <static> var reflParams$Cache1: Array[java.lang.Class] = Array[java.lang.Class]{}; @volatile private <synthetic> <static> var reflPoly$Cache1: scala.runtime.MethodCache = new scala.runtime.EmptyMethodCache(); <synthetic> <static> def reflMethod$Method1(x$1: java.lang.Class): java.lang.reflect.Method = { var method1: java.lang.reflect.Method = T.reflPoly$Cache1.find(x$1); if (method1.ne(null)) return method1 else { method1 = x$1.getMethod("id", T.reflParams$Cache1); T.reflPoly$Cache1 = T.reflPoly$Cache1.add(x$1, method1); return method1 } }; def main(args: Array[java.lang.String]): Unit = { val e: java.lang.Object = { new T$$anon$1() }; scala.this.Predef.assert(scala.Int.unbox({ val qual1: java.lang.Object = e; { var exceptionResult1: java.lang.Object = _; try { exceptionResult1 = T.reflMethod$Method1(qual1.getClass()).invoke(qual1, Array[java.lang.Object]{}) } catch { case ($1$ @ (_: java.lang.reflect.InvocationTargetException)) => { exceptionResult1 = throw $1$.getCause() } }; exceptionResult1 }.$asInstanceOf[java.lang.Integer]() }).==(5)) }; def this(): object T = { T.reflParams$Cache1 = Array[java.lang.Class]{}; T.reflPoly$Cache1 = new scala.runtime.EmptyMethodCache(); T.super.this(); () } }; final class T$$anon$1 extends java.lang.Object { private[this] var id: Int = _; <accessor> def id(): Int = T$$anon$1.this.id; <accessor> def id_=(x$1: Int): Unit = T$$anon$1.this.id = x$1; private[this] var name: java.lang.String = _; <accessor> def name(): java.lang.String = T$$anon$1.this.name; <accessor> def name_=(x$1: java.lang.String): Unit = T$$anon$1.this.name = x$1; def this(): T$$anon$1 = { T$$anon$1.super.this(); T$$anon$1.this.id = 5; T$$anon$1.this.name = "Prashant"; () } } }