scala - 矩形类(对象)可以有两个内在参数长度和宽度。如何编写(独立)函数来计算面积?

标签 scala

这是我为 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 类):

  1. 给定长和宽,计算矩形的面积
  2. 给定长度和面积,计算矩形的宽度
  3. 给定宽度和面积,计算矩形的长度
  4. 给定矩形对象,显示长度、宽度和面积

这个问题是在浏览了 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/

相关文章:

scala - 如何获取刚刚由 ScalaQuery 插入的自增 ID

scala - 如何使用 play-json 编写和读取空案例类?

Java:隐式类型转换,或隐式 toString() 调用

scala - 多态类型的类型类遭受类型删除

Scala - 类型 T 或 => T 的参数

scala - Scala 的 += 在 Int 的上下文中定义在哪里?

json - 如何获取searchHit的json字符串?

scala - 如何使用 `ProjectRef` 来引用 sbt 1.x 中的本地项目?

android - 将数据从运行时存储转换为案例类

scala - 何时使用 countByValue 何时使用 map().reduceByKey()