当前位置: 首页 > 知识库问答 >
问题:

无变量scala编程

刘瀚
2023-03-14

val和var在scala中,我认为这个概念是可以理解的。

我想做这样的事情(类似java):

trait PersonInfo {
  var name: Option[String] = None
  var address: Option[String] = None
  // plus another 30 var, for example 
 }
case class Person() extends PersonInfo
object TestObject {
  def main(args: Array[String]): Unit = {
         val p = new Person()
         p.name = Some("someName")
         p.address = Some("someAddress")
  }
}

这样我就可以更改姓名、地址等。。。

这工作得很好,但问题是,在我的程序中,我最终将所有内容都作为变量。据我所知,val在scala中是“首选”。val如何在这种类型的示例中工作,而不必在每次更改其中一个参数时重写所有30个参数?

也就是说,我可以

trait PersonInfo {
  val name: Option[String] 
  val address: Option[String] 
  // plus another 30 val, for example 
 }
case class Person(name: Option[String]=None, address: Option[String]=None, ...plus another 30.. ) extends PersonInfo
object TestObject {
  def main(args: Array[String]): Unit = {
         val p = new Person("someName", "someAddress", .....)
         // and if I want to change one thing, the address for example
         val p2 = new Person("someName", "someOtherAddress", .....)
  }
}

这是“正常”scala的做事方式吗(不受22个参数限制)?可以看出,我对这一切都很陌生。

起初托尼·K的基本选择是:

def with name(n:String)=个人(n,地址)

看起来很有前途,但我有很多扩展PersonInfo的类。这意味着在每一个版本中,我都必须重新实现defs,大量的打字、剪切和粘贴,只是为了做一些简单的事情。如果我将trait PersonInfo转换为一个普通类,并将所有def放入其中,那么我就有一个问题:如何返回一个人,而不是PersonInfo?在trait或super类中是否有一个聪明的scala东西可以实现,并让所有子类都真正扩展?

据我所知,在scala中,当示例非常简单,只有2个或3个参数时,所有这些都可以很好地工作,但当您有几十个参数时,它就会变得非常乏味,不可行。

古怪加拿大的人物背景我认为是相似的,仍然在思考这个。我想,如果我有43个参数,我需要分解成多个临时类,以便将参数输入到个人中。

复制选项也很有趣、神秘,但打字要少得多。

来自爪哇,我希望scala能提供一些巧妙的技巧。

共有3个答案

楚博雅
2023-03-14

Scala采用了函数式编程的许多范式,其中之一是专注于使用具有不可变状态的对象。这意味着在您的类中远离getter和setter,而是选择执行上面@Tony K.所建议的:当您需要更改内部对象的“状态”时,定义一个将返回一个新的Person对象的函数。

尝试使用不可变对象可能是Scala首选的方法。

关于22参数问题,您可以创建一个传递给Person的构造函数的上下文类:

case class PersonContext(all: String, of: String, your: String, parameters: Int)
class Person(context: PersonContext) extends PersonInfo { ... }

如果您发现自己经常更改地址,并且不想通过PersonContextrigamarole,您可以定义一种方法:

def addressChanger(person: Person, address: String): Person = {
    val contextWithNewAddress = ...
    Person(contextWithNewAddress)
}

你可以更进一步,在Person上定义一个方法:

class Person(context: PersonContext) extends PersonInfo {
    ...
    def newAddress(address: String): Person = {
        addressChanger(this, address)
    }
}

在你的代码中,你只需要记住当你更新你的对象时,你经常会得到新的对象作为回报。一旦你习惯了这个概念,它就会变得很自然。

芮明知
2023-03-14

scala中存在var的原因是支持可变状态。在某些情况下,可变状态确实是您想要的(例如,出于性能或清晰度原因)。

不过,你是对的,在鼓励使用不变状态的背后有很多证据和经验。在很多方面(并发性、清晰的理由等),事情都会做得更好。

您的问题的一个答案是为有问题的类提供修改器方法,这些方法实际上不会改变状态,而是返回一个带有修改条目的新对象:

case class Person(val name : String, val address : String) {
   def withName(n : String) = Person(n, address)
   ...
}

这个特定的解决方案确实涉及到对可能很长的参数列表进行编码,但只在类本身中进行编码。it用户可以轻松使用:

val p = Person("Joe", "N St")
val p2 = p.withName("Sam")
...

如果您考虑想要改变状态的原因,那么事情就变得更清楚了。如果您从数据库中读取数据,您可能有许多原因来改变对象:

  • 数据库本身已更改,您希望自动刷新内存中对象的状态
  • 您想对数据库本身进行更新
  • 你想要传递一个对象,并让它通过各种方法进行变异

在第一种情况下,不可变状态很容易:

val updatedObj = oldObj.refresh

第二个要复杂得多,有很多方法可以处理它(包括带有脏字段跟踪的可变状态)。看看像Squery这样的库是值得的,在那里你可以用一个漂亮的DSL编写东西(见http://squeryl.org/inserts-updates-delete.html),并且完全避免使用直接对象突变。

最后一个是由于复杂性的原因,您通常希望避免的。这样的事情很难并行化,很难推理,并导致各种错误,其中一个类引用了另一个类,但不能保证它的稳定性。这种用法是我们正在谈论的形式的不可变状态的用法。

田宇
2023-03-14

案例类有一个预定义的copy方法,您应该使用这个方法。

case class Person(name: String, age: Int)

val mike = Person("Mike", 42)

val newMike = mike.copy(age = 43)

这是怎么回事copy只是编译器为您编写的方法之一(除了equalshashCode等)。在这个例子中,它是:

def copy(name: String = name, age: Int = age): Person = new Person(name, age)

此方法中的值nameage隐藏外部范围中的值。如您所见,提供了默认值,因此您只需要指定要更改的值。其他默认为当前实例中的内容。

 类似资料:
  • 主要内容:变量声明,变量类型声明,变量类型引用,Scala 多个变量声明变量是一种使用方便的占位符,用于引用计算机内存地址,变量创建后会占用一定的内存空间。 基于变量的数据类型,操作系统会进行内存分配并且决定什么将被储存在保留内存中。因此,通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字母。 变量声明 在学习如何声明变量与常量之前,我们先来了解一些变量与常量。 一、变量: 在程序运行过程中其值可能发生改变的量叫做变量。如:时间,年龄。 二、常量 在

  • 变量是一种使用方便的占位符,用于引用计算机内存地址,变量创建后会占用一定的内存空间。 基于变量的数据类型,操作系统会进行内存分配并且决定什么将被储存在保留内存中。因此,通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字母。 变量声明 在学习如何声明变量与常量之前,我们先来了解一些变量与常量。 一、变量: 在程序运行过程中其值可能发生改变的量叫做变量。如:时间,年龄。 二、常量 在

  • 问题内容: 您如何声明和初始化要在Play2 Scala模板中本地使用的变量? 我有这个: 在模板的顶部声明,但它给了我这个错误: 问题答案: 基本上,您必须包装要使用它的块

  • 本文向大家介绍Scala概述| Scala编程教程,包括了Scala概述| Scala编程教程的使用技巧和注意事项,需要的朋友参考一下 Scala是Martin Odersky开发的一种编程语言。它于2003年投放市场。Scala代表可扩展语言。Scala是一种基于Java的编程语言,比Java更容易编码。因此被视为企业软件开发中Java的未来替代品。 Scala编程语言的功能 Scala的一些功

  • Persistant compile identifier. As an alternative to passing the same compile_id to each and every function call, you can set this compile_id and it will be used implicitly thereafter. 永久的编译鉴别号.作为一个可选办

  • Specifies the name of the compiler class that Smarty will use to compile the templates. The default is 'Smarty_Compiler'. For advanced users only.指定Smarty用来编译模板的编译类名.默认为:'Smarty_Compiler'.仅适合于高级用户.