Customize switch/when of Swift/Kotlin
- Swift and Kotlin, which are mainly used for Mobile Application, have more powerful functions than their based languages - Java and Objective-C, and the two langauges have similar functions.
I think that many people using those language love Non-Null
and Extension-Function
, but that few people use Customized-Switch-Statement
. You can create your switch-condition in both languages. and it's useful (when properly used).
In this article, I'll make customized switch(when)-case
that takes 2D-Point
as a paremeter and checks the point within specified Rectangle
areas.
Swift
In Swift, You need to create ~= Custom Opertion
The the type of first argument is the type used in case
condition and the second is the parameter passed to switch
statement.
Here's an example:
struct Point { let x: Int let y: Int } struct Rectangle { let x: Int let y: Int let w: Int let h: Int } //custom operation //return true when r contains p. func ~=(r: Rectangle, p: Point) -> Bool { (r.x...(r.x + r.w)).contains(p.x) && (r.y...(r.y + r.h)).contains(p.y) } // let p = Point(x: 5, y: 10) let ra = Rectangle(x: 1, y: 1, w: 5, h: 5) //not contains p let rb = Rectangle(x: 3, y: 4, w: 8, h: 10) //contains p let rc = Rectangle(x: 10, y: 1, w: 10, h: 20) //contains p // switch p { case ra: print("A") case rb: print("B") //match case rc: print("C") default: print("Default") } //Result // B
This function is not only used in switch
but also in if
condition. (Because it is only a operator function!)
if r1 ~= p { print("A") } else if r2 ~= p { print("B") } else if r3 ~= p { print("C") } else { print("Default") }
You should consider the balance of Writability and Readability
. These functions sometimes make your code less readable.
Kotlin
To create similar program in Kotlin, you need to create contains
in Rectangle.
object IsEven { operator fun contains(value: Int): Boolean { return (value % 2) == 0 } } fun main() { for (i in 0..5) { when (i) { // use `in` keyword in IsEven -> println(i) else -> {} } } } //Result // 0 // 2 // 4
To adapt Point and Rectangle problem that we saw above, create contains method in Rectangle
class.
data class Point(val x: Int, val y: Int) data class Rectangle(val x: Int, val y: Int, val w: Int, val h: Int) { operator fun contains(p: Point): Boolean { return this.x <= p.x && p.x < (this.x + this.w) && this.y <= p.y && p.y < (this.y + this.h) } } fun main() { val p = Point(3, 4) val r1 = Rectangle(1, 2, 1, 2) val r2 = Rectangle(2, 3, 4, 2) when (p) { in r1 -> println("R1") in r2 -> println("R2") else -> println("Nothing") } } //Result // R2
Another way: You can create special class for when-pattern.
data class Point(val x: Int, val y: Int) data class Rectangle(val x: Int, val y: Int, val w: Int, val h: Int) class RectCheck(val r: Rectangle) { operator fun contains(p: Point): Boolean { return r.x <= p.x && p.x < (r.x + r.w) && r.y <= p.y && p.y < (r.y + r.h) } } fun main() { val p = Point(3, 4) val r1 = Rectangle(1, 2, 1, 2) val r2 = Rectangle(2, 3, 4, 2) when (p) { in RectCheck(r1) -> println("R1") in RectCheck(r2) -> println("R2") else -> println("Nothing") } }
This pattern enables you to create more complex pattern for it can handle two or more arguments that are passed to the constructor (or instance-variable: I suppose this makes code complex).
Conclusion
In this article I showed the way to create custom when(switch) pattern.
This sometime enables you to write code easily but sometimes make the code less-readability. Please be careful when you use these patterns.
Enjoy Coding!
今回はプログラミングネタでいってみました。それも初心者ネタでなく、初心者から中級者ぐらい向けのネタでしょうか?
タイトルは短く、かつキャッチーにしたいので本文以上に難しいですね。
あと接続詞を使わないようにするのがむずかしい。日本人的に使ってしまう(テキトーな英語記事みてると意外と使われている気はしますが。禁じ手らしい文頭Butなどなど)
付け加えるなら、普通は上記の機能を使わなくても組めます。というより便利になるケースがあるかな?(本文といってること違いますが...)。
自分も以前ちらっと見たことはあったのですが詳細は知らなかったので、調べ上げて記事にしてみました。いい勉強になりました。
ちなみに記事作成に約2時間。うち1時間半は調べ物でググってコードを書いてただけです。あまり英語練習になってません(笑) そもそも英語の量が少ないですからね...
また自分でもまとめれそうなネタあったら書いていきたいと思います