【问题标题】:Why can't you create a setter without getter in scala?为什么你不能在 scala 中创建一个没有 getter 的 setter?
【发布时间】:2017-01-01 06:39:56
【问题描述】:

我在Scala: can't write setter without getter? 中发现没有getter 就无法创建setter:

对赋值的解释 一个简单的变量 x = e 取决于 x的定义。如果 x 表示一个 可变变量,然后赋值 将 x 的当前值更改为 评估结果 表达式 e. e 的类型是 期望符合 x 的类型。 如果 x 是无参数函数 在某些模板中定义,并且相同 模板包含一个 setter 函数 x_= 作为成员,然后赋值 x = e 被解释为调用 该 setter 函数的 x_=(e)。 类似地,分配 f.x = e 到 无参数函数 x 是 解释为调用 f.x_=(e )。赋值 f(args) = e 与 左侧的功能应用程序 ‘=’ 操作符被解释为 f.update(args, e ) ,即调用 由 f 定义的更新函数。

因此,不允许没有 getter 的 setter 是一个设计决定。但为什么? 是更难实施还是根本不可能做到?

我确实有一个有效的用例,将它用作(有些复杂的)设置器,不使用这种语法糖会破坏项目中任何地方的相同语法。

【问题讨论】:

  • 你能解释一下情况吗?为什么有一个 getter 是一个问题
  • @NathanielFord 问题在于它是 api 的一部分,它会让用户误以为可以使用 getter。情况:A 类的对象有一个设置某个值的 setter。以某种方式“连接”到 A 类对象的 B 类对象能够使用其同名的 getter 获取此值。把它想象成两个设备之间有一根电线,其中一个设备只有一个输出,这是另一个设备的输入:(在 A 类中)out.value = 3.0 和(在 B 类中)println(in.value )
  • @coolcat007:在这种情况下,您可能应该使用显式设置方法而不是赋值。
  • @coolcat007 Bergi 说了什么。但也要注意 S.O.不擅长回答“为什么会这样”的问题,而只会回答“我能做些什么来处理这样的事实”的问题。在您的情况下,您似乎应该为内部隐藏值编写自己的设置器。 Scala 这样做的“原因”是他们希望能够在编译器中做出简化生活的假设:成对的 getter 和 setter 就是这样做的。
  • @NathanielFord 我认为 scala 目前的工作方式确实最好创建一个显式设置器,尽管在我看来这在代码中看起来很难看,这是导致使用 Scala 是为了让我不必在每个 setter 中都使用“set”这个词。我正在查看 scala 编译器源代码,但找不到 _= 转换的实现位置。它是在 nsc.transform 包中的某个地方,还是我看错了位置?

标签: scala setter design-decisions


【解决方案1】:

您可以尝试这样从您的 API 中排除访问者:

scala> class C { def c_=(i: Int) = println(i) ; private def c: Int = ??? }
defined class C

scala> val c = new C
c: C = C@289fdb08

scala> c.c = 42
<console>:14: error: method c in class C cannot be accessed in C
val $ires0 = c.c
               ^
<console>:12: error: method c in class C cannot be accessed in C
       c.c = 42
         ^

scala> def f = { c.c = 42 ; 0 }
<console>:12: error: method c in class C cannot be accessed in C
       def f = { c.c = 42 ; 0 }
                   ^

在第一个错误中,REPL 正在尝试使用访问器报告值。

这种成对的访问器和修改器的概念被称为通用访问原则,因此被访问的成员看起来像一个属性。

表达式c.c 必须在进一步去糖之前进行类型检查。否则,转换(对c.c_= 的调用)必须是纯语法的。

例如,提供扩展方法c_= 的隐式转换可能会发挥作用。

【讨论】:

  • 你回答的最后两段让我有点困惑。你到底是什么意思?
  • 只是 c.c 必须有其自身的含义。如果您说c.c = 仅表示c.c_=,那么隐式转换可以添加c_= 突变体。这距离拥有一个简单的属性还有很长的路要走。
  • 考虑pastebin.com/yxsmumG3(是的,我知道,有点咸...)它可能不是一个“简单”的属性,但用法很清楚,可以看出getter @ 987654332@ 永远不会被使用,而password_= 是这个例子的核心部分的一半。我可以将password_= 重命名为setPassword 并显式调用该方法,但随后我们又回到了使用Good Old Java 时的状态。留下密码 getter 会使任何使用 API 的人感到困惑。
  • 我想我关于什么是property 的论点没有说服力。但如果问题是,你希望做什么,那么生态系统中充斥着赋值运算符,它们是以 = 结尾的操作。所以你可以password ~= "secret",其中波浪号提醒你在设置值之前应用了 mumbo-jumbo 哈希。查看 sbt 中的各种操作,&lt;++=scala-sbt.org/0.13.12/api/index.html#index.index-_
  • 好的,别管我的最后一条评论:twitter.com/eed3si9n/status/769029653700968448
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-09
  • 2018-11-28
  • 1970-01-01
相关资源
最近更新 更多