这是我为 Rectangle 类编写的代码。
class Rectangle (l: Double, w: Double) {
require (l > 0, w > 0)
val length = l
val width = w
def this (l: Double) = this (l, l)
def setDimensions (l: Double, w: Double) = new Rectangle (l, w)
def setLength (l: Double) = new Rectangle (l, width)
def setWidth (w: Double) = new Rectangle (length, w)
}
我的问题是如何在 Scala 中编写以下函数(独立于 Rectangle 类):
- 给定长和宽,计算矩形的面积
- 给定长度和面积,计算矩形的宽度
- 给定宽度和面积,计算矩形的长度
- 给定矩形对象,显示长度、宽度和面积
这个问题是在浏览了 this article 中的以下段落后出现的。 :
Functional languages get their name from the concept that programs should behave like mathematical functions; in other words, given a set of inputs, a function should always return the same output. Not only does this mean that every function must return a value, but that functions must inherently carry no intrinsic state from one call to the next. This intrinsic notion of statelessness, carried over into the functional/object world to mean immutable objects by default, is a large part of why functional languages are being hailed as the great saviors of a madly concurrent world.
请注意,作为 Scala 初学者,我正在努力掌握其中的 FP 部分。
最佳答案
这里有一个例子:
case class Rectangle(length: Double, width: Double) {
require (length > 0, width > 0)
lazy val area = length * width
override def toString = s"length: $length, width: $width, area: $area"
}
object Rectangle {
def fromLength(length: Double) = Rectangle(length, length)
def fromLengthArea(length: Double, area: Double) = Rectangle(length, area / length)
def fromWidthArea(width: Double, area: Double) = Rectangle(area / width, width)
def show(rect: Rectangle) = println(rect)
}
// Usage
Rectangle show Rectangle(2, 3)
Rectangle show Rectangle.fromLength(2)
Rectangle show Rectangle.fromLengthArea(2, 6)
Rectangle show Rectangle.fromWidthArea(3, 6)
我建议您始终在适当的情况下对类进行大小写,尤其是像 Rectangle
这样的类。
show
方法需要打印结果,因此在这种情况下无法避免副作用。换句话说,这个函数不是引用透明的。实际上,Rectangle
的整个构造函数可以被认为不是引用透明的,因为您正在使用 require
。您可以通过确保 Rectangle 始终在类外部的某个位置接收到正确的值来避免这种情况,但是当由于验证而无法创建 Rectangle 类时,您还需要返回一些内容错误。您可以使用 Option 类来实现此目的。这是一个小例子:
case class Rectangle private (length: Double, width: Double) {
lazy val area = length * width
override def toString = s"length: $length, width: $width, area: $area"
}
object Rectangle {
def fromLengthWidth(length: Double, width: Double) =
validating(length, width)(new Rectangle(length, width))
def fromLength(length: Double) = validating(length) {
new Rectangle(length, length)
}
def fromLengthArea(length: Double, area: Double) = validating(length, area) {
new Rectangle(length, area / length)
}
def fromWidthArea(width: Double, area: Double) = validating(width, area) {
new Rectangle(area / width, width)
}
def show(rect: Option[Rectangle]) = println(rect getOrElse "Invalid Rectangle!!!")
private def validating[R](values: Double*)(fn: => R) =
if (values forall (_ > 0)) Some(fn)
else None
}
Rectangle show Rectangle.fromLengthWidth(2, 3)
Rectangle show Rectangle.fromLength(0)
// prints:
// length: 2.0, width: 3.0, area: 6.0
// Invalid Rectangle!!!
正如您所看到的,我将构造函数设置为私有(private),并将验证移至伴随对象中(可以访问具有相同名称的类的私有(private)成员)。所以你不能创建无效的矩形。但这里重要的一点是,即使您提供了 splinter 的长度,您仍然会收到一些东西(在本例中它是 None
对象,它是 Option
类的实例和子类)。
我在类中添加了 area
方法,但是您当然可以编写一个独立的方法或函数来计算面积:
def area(rect: Rectangle) = rect.length * rect.width
或
val area = (rect: Rectangle) => rect.length * rect.width
我希望这能帮助您理解这个主题。如果仍然不清楚(或者我的回答没有涵盖您真正想知道的内容),请不要犹豫,发表评论。
关于scala - 矩形类(对象)可以有两个内在参数长度和宽度。如何编写(独立)函数来计算面积?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10953544/