在C#中你可以写:
var e = new { ID = 5, Name= "Prashant" };
assertEquals( 5, e.ID )
Run Code Online (Sandbox Code Playgroud)
但在Scala中我最终写道:
var e = (5, "Prashant")
assertEquals( 5, e._1 )
Run Code Online (Sandbox Code Playgroud)
Scala通过使用泛型来保持类型安全(就像C#一样),但是丢失了每个字段名称的可读性,例如我使用"_1"而不是"ID".
Scala中有这样的东西吗?
Dan*_*ral 19
object T {
def main(args: Array[String]) {
val e = new { var id = 5; var name = "Prashant" }
assert(e.id == 5)
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,让我们说清楚.这确实使用了对Scala 2.7和Scala 2.8的反射,因为e
在这种情况下,类型是Scala通过反射处理的结构类型.这是生成的代码,在清理时间(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();
()
}
}
}
Run Code Online (Sandbox Code Playgroud)
有一些缓存正在进行,但如果我在它之间交替id
,name
它将使缓存无效.Scala 2.8也可以进行反射,也可以进行缓存,但它使用了更高效的缓存技术,可以提供更好的整体性能.作为参考,这里是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";
()
}
}
}
Run Code Online (Sandbox Code Playgroud)
ams*_*ams 14
您还可以命名要分配的元组的部分,如:
val (ID, Name) = (5, "Prashant")
assertEquals( 5, ID )
Run Code Online (Sandbox Code Playgroud)
你也可以这样使用:
val (ID, Name, Age) = functionThatReturnsATuple3
println("ID: " + ID + ", age: " + Age)
Run Code Online (Sandbox Code Playgroud)
当我第一次阅读有关_x
语法时,我认为它很棒并且使用了很多.因为我已经基本上使用它,当我要看看代码,我两个月前写我需要花时间的负载试图找出什么类型的停止_1
,_2
等都是.我认为后见之明显然id
比它更具可读性pair._1
.
这也可以在诸如以下的功能中使用map
,filter
例如:
val list: List[ (Int, String, Double) ] = ...
list map { case (id, name, time) => ... }
list filter { case (_, name, _) => name == "X" }
Run Code Online (Sandbox Code Playgroud)
请注意,filter
您可以_
在函数体中使用s表示不会使用的元素.当浏览这样的代码以确定正在使用哪些结构部分以及如何构建值时,这可能很有用.
我只想做一个案例类:
object Yo{
case class E(id: Int, name: String)
def main(){
val e = E(5,"Prashant")
println("name="+e.name+", id="+e.id)
}
}
Run Code Online (Sandbox Code Playgroud)
不确定它是否与丹尼尔的答案一样有效但我希望它是相同的(我很感激对此的评论).在任何情况下,我发现它更具可读性,如果你有多个实例,只使用一个共享的额外行E
.您还可以向case类添加方法,例如:
case class E(id: Int, name: String){
def hasId(id: Int) = this.id==id
}
val e = E(5,"Prashant")
assert(e hasId 5)
Run Code Online (Sandbox Code Playgroud)
正如Juh_所建议的,扩展案例类应该做你想要的:
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
Run Code Online (Sandbox Code Playgroud)
Case类提供了一个equals方法,它们还扩展了Product
trait,这与Scala元组扩展的特性相同.也许将来他们也会扩展这些ProductN
特质.
如果您按照其他答案中的建议使用匿名类,那么您最终不会得到真正的元组!例如,您没有获得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
Run Code Online (Sandbox Code Playgroud)
从Scala 2.11扩展开始Tuple2
工作,但这是不推荐使用的,因为你不应该扩展case类.
您也可以扩展Product2
特性,但这不提供任何方法的实现,因此您必须自己编写所有方法.
您可能还可以使用Shapeless HList
,它会以添加外部依赖项为代价为您提供许多花哨的功能.
我也试过Twitter的jaqen库,但是在Scala 2.11中我没有为我编译.
我目前正在使用Scala 2.11,因此我无法保证此建议适用于其他版本的Scala.
归档时间: |
|
查看次数: |
15028 次 |
最近记录: |