Scalaの.copyについて

ごあいさつ

こんにちは。meviyのWebシステムを開発している谷平です。
Scala.copyはケースクラスにおいて便利な機能の1つです。
本記事では、.copyの便利な点やJavaとの比較、ユニットテストでの活用例を紹介します。

.copyの便利な点

.copyは、オブジェクトを新しく作成しながら、特定のフィールドだけを変更できる機能です。 ケースクラスを用いると、手軽に値の一部を変更した新しいインスタンスを生成できます。

使用例

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

val user1 = User("Alice", 25)
val user2 = user1.copy(age = 26)

println(user1) // User(Alice,25)
println(user2) // User(Alice,26)

このように、user1を基にageだけを変更したuser2を簡単に作成できます。

Javaとの比較

Javaでは、オブジェクトの特定のプロパティを変更するには、新しいインスタンスを作成し、すべてのフィールドに値を設定する必要があります。

Javaでの例

class User {
    private final String name;
    private final int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User copyWithAge(int newAge) {
        return new User(this.name, newAge);
    }
}

User user1 = new User("Alice", 25);
User user2 = user1.copyWithAge(26);

Javaでは.copyのような便利な機能がなく、自前でコピー用のメソッドを用意する必要があります。

ユニットテストでの活用例

.copyユニットテストでも非常に便利です。たとえば、テストデータの一部だけ変更したい場合に、.copyを活用すると簡潔にコードを書けます。

import org.scalatest.freespec.AnyFreeSpec

case class Order(unitPrice: Int, quantity: Int, taxRate: Double) {
  def totalPrice: Double = unitPrice * quantity * (1 + taxRate)
}

class OrderSpec extends AnyFreeSpec {
  "異なる消費税率に応じて正しく合計金額を計算できる" in {
    val baseOrder = Order(unitPrice = 100, quantity = 2, taxRate = 0.1) // デフォルトはイートインの消費税
    
    val eatInOrder = baseOrder.copy(taxRate = 0.1) // イートインの消費税 10%
    val takeOutOrder = baseOrder.copy(taxRate = 0.08) // テイクアウトの消費税 8%
    
    assert(eatInOrder.totalPrice == 220)  // (100 * 2) * 1.1 = 220
    assert(takeOutOrder.totalPrice == 216) // (100 * 2) * 1.08 = 216
  }
}

このように、.copyを使うことで、基本となるデータを基に異なる税率を適用したテストデータを簡単に作成できます。

まとめ

Scala.copyには以下の特長があります。Scalaを使う際はぜひ活用してみてください!

Scalaには様々な機能があり、それらを活用することでより簡潔にコードを書くことができます。
本ブログでは他にもScalaに関する記事がありますので、ぜひご覧いただけると幸いです。

さいごに

本ブログではDTダイナミクスで用いている技術やプロダクト、組織などの魅力を発信しています。 少しでも興味を持っていただけた方は、ぜひお気軽にカジュアル面談へ応募いただけると嬉しいです!