据说我有以下内容
case class test {
a:string
b: string
c: Int
d: Int }
var temp = List(test("lol","lel",1,2))
var total = List(test)
total = total:::temp //this doesn't work because temp is of type [test] while total is of type [test.type]
我不明白其中的区别。 我想使用它的原因是我想有一个运行列表,其中元素将被有条件地添加到循环中。 因此,在这种情况下,total
最初应该是一个空列表,其中包含test
对象。我该怎么做?
任何反馈不胜感激!
让我先解释一下关于 Scala 的一些基础知识。
在 Scala 中,你定义了一个类,如下所示,
scala> class Demo(a: String, b: Int) {
| def stringify: String = a + " :: " + b
| }
// defined class Demo
您可以将class
视为提供给 Scala 的蓝图,该蓝图将用于创建该class
的实例。在这里,class Demo
的每个实例都将有两个属性 -a
将是一个String
,b
将是一个Int
和一个方法 -stringify
将返回一个String
。
scala> val demo1 = new Demo("demo1", 1)
// demo1: Demo = Demo@21eee94f
scala> demo1.getClass
// res0: Class[_ <: Demo] = class Demo
这里demo1
是class
Demo
的一个实例,并且具有type
Demo
。
Scala还有一个object
的概念,它们是专门生成的内部类的实例。
scala> object OtherDemo {
| val a: Int = 10
| }
// defined object OtherDemo
scala> DemoObject.getClass
// res2: Class[_ <: OtherDemo.type] = class OtherDemo$
在这里,OtherDemo
将是该特殊生成的class
OtherDemo$
的唯一实例,并且具有type
OtherDemo.type
.
然后是斯卡拉的case class
scala> case class AnotherDemo(a: Int)
// defined class AnotherDemo
这不仅会创建一个class
AnotherDemo
,还会创建一个我们称之为伴随对象的object
AnotherDemo
。这相当于,
class AnotherDemo(a: Int)
object AnotherDemo {
def apply(a: Int): AnotherDemo = new AnotherDemo(a)
def unapply(anotherDemo: AnotherDemo): Option[Int] = Some(anotherDemo.a)
// And many more utility functions
}
我们称这种object
AnotherDemo
为class
AnotherDemo
companion object
。
我们可以通过两种方式创建AnotherDemo
实例,
// By using new keyword, as we can do for any class
scala> val anotherDemo1 = new AnotherDemo(1)
// anotherDemo1: AnotherDemo = AnotherDemo(1)
// Or we can use `apply` method provided by companion object
scala> val anotherDemo2 = AnotherDemo(2)
// anotherDemo2: AnotherDemo = AnotherDemo(2)
scala> anotherDemo1.getClass
// res6: Class[_ <: AnotherDemo] = class AnotherDemo
scala> anotherDemo2.getClass
// res7: Class[_ <: AnotherDemo] = class AnotherDemo
scala> AnotherDemo.getClass
// res8: Class[_ <: AnotherDemo.type] = class AnotherDemo$
此外,在 Scala 中,您的类名应该以大写字母开头。这使您能够轻松地将它们与应以小写字母开头的实例变量区分开来。这有助于您避免混淆。
现在,它应该是a: String
而不是a: string
.
scala> case class Test(
| a: String,
| b: String,
| c: Int,
| d: Int
| )
// defined class Test
现在,当你写作时,
scala> var temp = List(Test("lol","lel",1,2))
// temp: List[Test] = List(Test(lol,lel,1,2))
它实际上相当于,
var temp = List.apply(Test.apply("lol","lel",1,2))
或
val test1 = Test.apply("lol","lel",1,2)
var temp = List.apply(test1)
Test.apply
Test
不是你的class Test
而是companion object Test
。调用Test.apply
会返回一个class Test
实例,该实例正在传递给List.apply
,以最终获得包含此Test
实例的type
List[Test]
List
。
但是当你写这篇文章时,
scala> var total = List(Test)
// total: List[Test.type] = List(Test)
您正在创建类型为List[Test.type]
的List
,其中包含该companion object
Test
。
专注于total: List[Test.type]
部分......这意味着total
是type
List[Test.type]
的variable
,这意味着它将想要指向type
List[Test.type]
的value/instance
,并且会拒绝指向其他任何东西。
现在。。。你正在尝试这样做,
total = total ::: temp
这相当于,
val x = total ::: temp
total = x
这实际上是,
val x = temp.:::(total)
total = x
现在看看这个val x = total ::: temp
,
scala> val x = total ::: temp
// x: List[Serializable] = List(Test, Test(lol,lel,1,2))
你看。。。此x
属于List[Serializable]
类型。所以当你尝试total = x
时,你会得到以下错误,
scala> total = x
// <console>:13: error: type mismatch;
// found : List[Serializable]
// required: List[Test.type]
// total = x
// ^
这意味着total
需要List[Test.type]
但您正在给它一个List[Serializable]
。
您正在寻找total = List.empty[test]
而不是List(test)
。 前者创建一个List[test]
类型的空列表,后者是List[test.type]
类型的单元素列表(test.type
与test
不同 - 它是它自己的对象,表示test
实例的类型)。
另外,不要使用var
.它们是邪恶的,在 99% 的用例中并不是真正需要的。只要假装关键字根本不存在,直到你对语言有足够的把握,能够自信地区分其他1%。
当你这样做时:
var total = List(test)
您没有初始化对象测试,这就是为什么列表的类型是 Test.type,您只是为对象创建模板列表。
改为执行此操作时:var temp = List(test("lol","lel",1,2))
Yo 从模板(类,在本例中为 Test)实例化对象,因此 temp 的类型为List[Temp]
。
因此,如果您执行以下操作:
val template = Test
那么 t 的类型是Test.type
你可以像这样从template
实例化一个对象 Test:
val instantiated = template("lol","lel",1,2)
正如您在示例中所看到的,total
变量只是一个模板列表,您可以从中实例化对象,而temp
变量是 Test 类型的对象列表。
要创建 Test 类型的对象的空列表,您只需执行以下操作:
val t: List[Test] = List.empty
然后,您可以将任何对象(类型为Test
)添加到此列表中
根据您的描述("我想要一个运行列表,其中元素将被有条件地添加到循环中"),我的理解是,您正在从某个来源获取Test
对象并希望将它们放入列表中,但前提是它们满足某些条件。我们可以将此要求表示为一种方法。为方便起见,我们将该方法放在Test
伴随对象中。伴随对象是放置应该可用的内容而无需实例化任何对象的地方。
case class Test(a: String, b: String, c: Int, d: Int)
object Test {
/**
Returns a list of `Test` objects that pass the given criteria.
@param tests some source of tests that we can loop over one at a
time.
@param condition checks whether a `Test` object should go into our
output list.
*/
def runningList(
tests: Iterable[Test])(condition: Test => Boolean): List[Test] =
tests.filter(condition).toList
}
您可以像这样使用它(例如):
Test.runningList(testsSource) { test => test.c > 0 && test.d < 100 }
正如你在这里看到的,我使用了一些 Scala 功能,比如可迭代对象及其列表转换方法、多参数列表方法、一类函数、函数作为最后一个参数 DSL 等。如果您对这些主题有更多疑问,我建议您使用 Scala 教程。