编辑:提示此问题的错误现已修复。
在 Scala Reference 中,我可以阅读(第 86 页):
对简单变量 x = e 赋值的解释取决于 x 的定义。如果 x 表示可变变量,则赋值将 x 的当前值更改为计算表达式 e 的结果。e 的类型应该符合 x 的类型。如果 x 是在某个模板中定义的无参数函数,并且同一模板包含一个 setter 函数 x_= 作为成员,则赋值 x = e 被解释为该 setter 函数的调用 x_=(e)。类似地,对无参数函数 x 的赋值 f.x = e 被解释为调用 f.x_=(e)。
因此,例如,这样的事情可以正常工作:
class A {
private var _a = 0
def a = _a
def a_=(a: Int) = _a = a
}
然后我可以写
val a = new A
a.a = 10
但是如果我这样定义类,在方法a中添加一个类型参数:
class A {
private var _a = 0
def a[T] = _a
def a_=(a: Int) = _a = a
}
然后它不再起作用了;error: reassignment to val
如果我写的话,我会得到一个a.a = 10
。有趣的是,例如,它仍然可以在没有类型参数和隐式参数列表的情况下工作。
可以说,在这个例子中,类型参数不是很有用,但是在 DSL 的设计中,即使 getter 有类型参数,也可以调用 setter 方法(顺便在 setter 上添加类型参数)被允许并且工作正常)。
所以我有三个问题:
- 有解决方法吗?
- 当前的行为是否应该被视为错误?
- 为什么编译器强制使用 getter 方法以允许使用 setter 的语法糖?
更新
这就是我真正想做的事情。它相当长,抱歉,我本打算避免使用它,但我意识到省略它会更令人困惑。
我正在使用 Scala 中的 SWT 设计 GUI,并且使用 Dave Orme 的XScalaWT获得了极大的乐趣,这极大地减少了所需代码的数量。这是他的博客文章中的一个示例,内容是关于如何创建Composite
将°C 转换为°F 度的 SWT:
var fahrenheit: Text = null
var celsius: Text = null
composite(
_.setLayout(new GridLayout(2, true)),
label("Fahrenheit"),
label("Celsius"),
text(fahrenheit = _),
text(celsius = _),
button(
"Fahrenheit => Celsius",
{e : SelectionEvent => celcius.setText((5.0/9.0) * (fahrenheit - 32)) }
),
button(
"Celsius -> Fahrenheit",
{e : SelectionEvent => fahrenheit.setText((9.0/5.0) * celsius + 32) })
)
)
每个小部件构造方法的参数都是 type ,带有一些有用的隐式转换,例如允许直接为具有方法(WidgetType => Any)*
的小部件指定字符串。setText()
所有构造函数都是从单例对象导入的。
最后,我希望能够按照这些思路写一些东西:
val fieldEditable = new WritableValue // observable value
composite(
textField(
editable <=> fieldEditable,
editable = false
),
checkbox(
caption = "Editable",
selection <=> fieldEditable
)
)
这将通过 WritableValue 变量将文本字段的可编辑属性绑定到复选框的选择。
首先:命名参数在这里不适用,所以该行editable = false
必须来自某个地方。因此,沿着单例对象中的小部件构造方法,我可以在概念上编写,
def editable_=[T <: HasEditable](value: Boolean) = (subject: T) => subject.setEditable(value)
...但这仅在吸气剂也存在时才有效。太好了:无论如何我都需要 getter 来实现与 <=> 的数据绑定。像这样的东西:
def editable[T <: HasEditable] = new BindingMaker((widget: T) => SWTObservables.observeEditable(widget))
如果这行得通,生活会很好,因为我可以在 BindingMaker 中定义 <=> 并且我可以使用这个很好的语法。但可惜的是,getter 上的类型参数破坏了 setter。因此我最初的问题是:为什么这个简单的类型参数会影响编译器是否决定继续使用语法糖来调用 setter?
我希望这使它现在更清楚一点。感谢阅读……</p>