Help us understand the problem. What is going on with this article?

Kotlinでスコープ関数「apply」を使えば、一時変数を書かなくてすむの巻

More than 1 year has passed since last update.

こんにちは。

:hatched_chick:Kotlinを学びだすと、「なんだコレは?コレを使って何がオイシいのか?」と、その存在意義を疑いたくなるような感覚に陥っている最中の私です。:baby_chick:

特に、スコープ関数の「apply」がよく分からなくて腹が立ち減ります。
あゝ君は誰が為にスコープ関数を使ふのか。

自分で作ったクラスで有難味を知る

Item.kt
class Item(id: String, name: String, price: Int) {
    val id: String = id
    var name = name
    var price = price // 単価(税抜価格)
    var taxRate = 0.00
    var salePrice: Int = (price * taxRate).toInt() // 売価(税込価格)

    // 消費税率を設定
    fun setUpTaxRate(rate: Double) {
        taxRate = rate
    }
}

商品を表すクラスです。

  • 1989年4月:消費税法を施行。税率は3%。:money_with_wings::money_with_wings::money_with_wings:
  • 1997年4月:税率を5%に引き上げ。:money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings:
  • 2014年4月:税率を8%に引き上げ。:money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings:
  • 2019年10月?:税率を10%に引き上げ予定。:money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings::money_with_wings:

選挙に行きましょう。:inbox_tray:

SalesMan.kt
class SalesMan {

    fun sale1(): Item {
        var item = Item("A001", "自動扉冷蔵庫", 100000)
        item.setUpTaxRate(1.08)
        item.salePrice = (item.price * item.taxRate).toInt()
        return item
    }

    fun sale2(): Item {
        return Item("A001", "自動扉冷蔵庫", 100000).apply {
            setUpTaxRate(1.08)
            salePrice = (price * taxRate).toInt()
        }
    }
}
  • sale1()メソッドは、フツーに書いてみました。
  • sale2()メソッドこそ、スコープ関数「apply」を使って、6か所も書いた"item"を書かずに済みました
実行してみます
fun main(args: Array<String>) {
    val i1 = SalesMan().sale1()
    println("税込${i1.salePrice}円")
    val i2 = SalesMan().sale2()
    println("税込${i2.salePrice}円")
}

実行結果は同じです(税込108000円)。:yen:この記事を投稿した時点では、10万円の買い物で、8千円が消費税です...。:expressionless:

この「同じことを何度も書かずに済んだ」の恩恵は、次にBuilderパターンが適用されたクラスだと、より有難味があるかと思います。なぜなら、Kotlinの公式サイト上のイデオム例のひとつに、「Builder-style usage of methods that return Unit」というのが記載されています。

Java SE のAPIを使ってみて有難味を知る

java.utilパッケージに、JDK 1.8から導入され、Builderパターンが適用されたCalendar.Builderがあります。:flag_jp:平成31年4月30日は、西暦で何年で、何曜日でしょうか?

以下3パターンはすべてコンパイルが通ります。

これは愚なるコードよ
    val cb = Calendar.Builder() // Builderインスタンスを生成し、
    cb.setCalendarType("japanese") // 和暦に対応させて、
    cb.setDate(31, Calendar.APRIL, 30) // 第1引数は、現在の元号の年を渡し、
    cb.setTimeOfDay(5, 6, 4) // 時分秒も設定して、
    val calendar = cb.build()

せっかくのBuilderパターンを使わないという暴挙。cbを5か所も書いている。:angry:

書き改めます。

Builderパターンに従えども...
    val calendar = Calendar.Builder()
    .setCalendarType("japanese")
    .setDate(31, Calendar.APRIL, 30)
    .setTimeOfDay(5, 6, 4)
    .build()

メソッドチェーン:chains:するというのが、正しい用法かとは思うのですが、でもね、細かいこと言わせていただきますと、「.」記号がね、目障りなんですよ。セミコロンですら書くのが億劫だからKotlin使いたいんですよ、私は。:thinking:

これが一等素敵
import java.text.SimpleDateFormat
import java.util.Calendar

fun main(args: Array<String>) {
    val calendar = Calendar.Builder().apply {
        setCalendarType("japanese")
        setDate(31, Calendar.APRIL, 30)
        setTimeOfDay(5, 6, 4)
    }.build()

    val formatDate = SimpleDateFormat("GGGGyyyy年MM月dd日(E) ahh時mm分ss秒")
    print(formatDate.format(calendar.time))
}

実行結果は、西暦2019年で、火曜日でした。今回、時分秒はテキトーです(この時刻にとある儀式が催されるわけではありません)。

西暦2019年04月30日(火) 午前05時06分04秒

ともあれ、applyを使用したら、なんと「.」記号すら書かずに済むようになりました。

これがスコープ関数「apply」の活きる道、なのかと思われます。

以上です。

wakwak
I want to be excited 'ʞɐʍ ʞɐʍ' life anytime. ˙ǝɯᴉʇʎuɐ ǝɟᴉl ,wak wak, pǝʇᴉɔxǝ ǝq oʇ ʇuɐʍ I
https://www.casareal.co.jp/
casareal
システム開発/評価・検証支援/品質改善支援サービスと現場に即した実践的なIT研修サービスを提供しています。
https://www.casareal.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした