
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ฌธ๋ฒ๋ค์ ๋ชจ๋ ํ์ฉํ๋ฉด, ์ฝ๋๋ฅผ ๋ ๊น๋ํ๊ฒ ์์ฑํ ์ ์์ต๋๋ค.
Scope ํจ์๋ ๊ฐ์ฒด๋ฅผ ์ด๊ธฐํํ๊ฑฐ๋ ์ฒด์ด๋ํ ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
data class AppSettings(
var width: Int = 0,
var height: Int = 0,
var frameRate: Int = 60,
var debug: Boolean = false
)
val settings = AppSettings()
settings.width = 800
settings.height = 600
settings.frameRate = 60
settings.debug = true
// ๋ณ์ ์ด๋ฆ์ ๋งค๋ฒ ๋ฐ๋ณตํด์ผ ํจ
val settings = AppSettings().apply {
width = 800
height = 600
frameRate = 60
debug = true
// this๊ฐ AppSettings์ด๋ฏ๋ก, ํ๋กํผํฐ์ ์ง์ ์ ๊ทผ
}
์ด ๊ธ์์๋:
์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
Scope ํจ์๋ ๊ฐ์ฒด์ ๋ฒ์(scope) ์์์๋ง ์๋ํ๋ ํจ์๋ค์ ๋๋ค.
๋ค ๊ฐ์ง๊ฐ ์์ต๋๋ค:
apply โ ๊ฐ์ฒด๋ฅผ ์์ ํ๊ณ ๋ฐํalso โ ๊ฐ์ฒด๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ฉฐ ๋ถ์ํจ๊ณผ ์คํlet โ ๋ณํ๋ ๊ฐ ๋ฐํrun โ ๋ณํ๋ ๊ฐ ๋ฐํ (์๋ฌต์ ๋ฆฌ์๋ฒ)apply โ ๊ฐ์ฒด ์ค์ ํ ๋ฐํapply๋ ๊ฐ์ฒด๋ฅผ ์ค์ ํ๊ณ ๊ทธ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
data class AppSettings(var width: Int = 0, var height: Int = 0)
val settings = AppSettings().apply {
width = 800
height = 600
}
// settings๋ ์ค์ ์ด ๋๋ ๊ฐ์ AppSettings ๊ฐ์ฒด์
๋๋ค.
apply ๋ธ๋ก์ ๋ฆฌ์๋ฒ๋ ์์ฑํ ๊ฐ์ฒด์ด๋ฏ๋ก this.width ๋์ width๋ก ์ ๊ทผํฉ๋๋ค. ๋ธ๋ก์์ ๋ฌด์์ ๋ฐํํ๋ apply์ ๊ฒฐ๊ณผ๋ ์๋ ๊ฐ์ฒด์
๋๋ค.
data class Circle(
var x: Double = 0.0,
var y: Double = 0.0,
var radius: Double = 10.0,
var color: ColorRGBa = ColorRGBa.WHITE
)
// apply ์์ด
val circle1 = Circle()
circle1.x = 100.0
circle1.y = 200.0
circle1.radius = 50.0
circle1.color = ColorRGBa.RED
// apply๋ก (๊น๋ํจ)
val circle2 = Circle().apply {
x = 100.0
y = 200.0
radius = 50.0
color = ColorRGBa.RED
}
val numbers = mutableListOf<Int>().apply {
add(1)
add(2)
add(3)
add(4)
add(5)
}
// ๋๋ ํ ์ค๋ก
val numbers = mutableListOf(1, 2, 3, 4, 5) // ๋ ๊ฐ๋จํจ
program {
val drawer = this.drawer.apply {
fill = ColorRGBa.WHITE
stroke = ColorRGBa.BLACK
strokeWeight = 2.0
}
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.circle(400.0, 400.0, 100.0)
}
}
also โ ๋ถ์ํจ๊ณผ ์คํ ํ ์๋ณธ ๋ฐํalso๋ ๊ฐ์ฒด๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ฉด์ ๋ถ์ํจ๊ณผ๋ฅผ ์คํํฉ๋๋ค.
val result = mutableListOf(1, 2, 3)
.also { list ->
println("List created: $list") // ๋ถ์ํจ๊ณผ
// also ์์ฒด๋ ๋ฐํ๊ฐ์ ๋ฐ๊พธ์ง ์์ง๋ง, list์ ๊ฐ๋ณ ๋ด์ฉ์ ์์ ํ ์ ์์ต๋๋ค.
}
// result๋ ์๋ณธ list์ ๊ฐ์
val numbers = (1..10).toList()
.also { println("Original: $it") }
.filter { it % 2 == 0 }
.also { println("Filtered: $it") }
.map { it * 2 }
.also { println("Mapped: $it") }
// ์ถ๋ ฅ:
// Original: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Filtered: [2, 4, 6, 8, 10]
// Mapped: [4, 8, 12, 16, 20]
data class Particle(
var position: Vector2,
var velocity: Vector2
)
val particles = (0 until 100)
.map { i ->
Particle(
position = Vector2(random(800.0), random(600.0)),
velocity = Vector2(random(-2.0, 2.0), random(-2.0, 2.0))
)
}
.also { particles ->
println("Created ${particles.size} particles")
}
.filter { it.position.x > 100 }
.also { filtered ->
println("Filtered to ${filtered.size} particles")
}
program {
val particles = mutableListOf<Particle>()
extend {
// ํํฐํด ์์ฑ ๋ฐ ๋ก๊น
particles.add(
Particle(mouse.position, Vector2(1.0, 0.0))
.also { p ->
println("Particle created at ${p.position}")
}
)
}
}
let โ ๋ณํ ํ ๋ฐํlet์ ๊ฐ์ฒด๋ฅผ ๋ณํํด์ ์๋ก์ด ๊ฐ์ ๋ฐํํฉ๋๋ค.
val original = "Hello"
val transformed = original.let { str ->
str.uppercase() + "!"
}
println(transformed) // "HELLO!"
// original์ ๋ณ๊ฒฝ๋์ง ์์
println(original) // "Hello"
val name: String? = "Mina"
// let์ผ๋ก null ์ฒดํฌ
name?.let { n ->
println("Hello, $n")
// n์ String (null์ด ์๋์ด ๋ณด์ฅ๋จ)
}
val point = Vector2(100.0, 200.0)
val distance = point.let { p ->
sqrt(p.x * p.x + p.y * p.y)
}
println(distance) // 223.6...
// ๋๋ ๋๋ค ์ถ์ฝ
val distance2 = point.let { sqrt(it.x * it.x + it.y * it.y) }
val result = mutableListOf(1, 2, 3)
.let { list ->
list.map { it * 2 } // List<Int>๋ก ๋ณํ
}
.let { doubled ->
doubled.sum() // Int๋ก ๋ณํ
}
println(result) // 12
program {
var selectedPoint: Vector2? = null
extend {
drawer.clear(ColorRGBa.BLACK)
// selectedPoint๋ก ๊ณ์ฐ ์ํ
selectedPoint?.let { point ->
val distance = (point - mouse.position).length
drawer.fill = if (distance < 100) ColorRGBa.RED else ColorRGBa.WHITE
drawer.circle(point.x, point.y, 20.0)
}
}
}
run โ ์๋ฌต์ ๋ฆฌ์๋ฒ๋ก ๋ณํrun์ ๋ฆฌ์๋ฒ๋ฅผ ์๋ฌต์ ์ผ๋ก ์ฌ์ฉํ๋ฉด์ ๋ณํ๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.
val result = "Hello".run {
// this == "Hello"
uppercase() + "!"
}
println(result) // "HELLO!"
// let๊ณผ ๋น์ทํ์ง๋ง, ํ๋ผ๋ฏธํฐ ๋์ this ์ฌ์ฉ
// let: let { str -> str.uppercase() }
// run: run { uppercase() }
val circle = Circle(100.0, 200.0, 50.0)
val area = circle.run {
PI * radius * radius
}
println(area) // 7853.98...
val input: String? = "pattern"
val result = input?.run {
if (this.isEmpty()) "Empty" else "Not empty: $this"
} ?: "Input is null"
println(result)
program {
data class Settings(var scale: Double = 1.0)
val settings = Settings().run {
scale = 2.0
this // ๋ง์ง๋ง ์์ด๋ฏ๋ก Settings ๊ฐ์ฒด ๋ฐํ
}
}
apply, also, let, run์ ๋ชจ๋ ๋ธ๋ก์ ์คํํ ๋ค ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค. ์ฐจ์ด๋ ๋ธ๋ก ์์์ ๊ฐ์ฒด๋ฅผ ์ด๋ค ์ด๋ฆ์ผ๋ก ๋ค๋ฃจ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ค ๊ฐ์ ๋ฐํํ๋์ง์ ์์ต๋๋ค. ํจ์ ์ข
๋ฅ์ ๋ฐ๋ผ ๋ธ๋ก์ ์์ ๊ฐ์ฒด๊ฐ ๋ฌ๋ผ์ง๋๋ค.
| ํจ์ | ํ๋ผ๋ฏธํฐ | ๋ฆฌ์๋ฒ | ๋ฐํ๊ฐ | ์ฉ๋ |
|---|---|---|---|---|
apply | ์์ | this | ๊ฐ์ฒด | ์ด๊ธฐํ |
also | it | ์์ | ๊ฐ์ฒด | ๋ถ์ํจ๊ณผ |
let | it | ์์ | ๋ณํ๊ฐ | ๋ณํ |
run | ์์ | this | ๋ณํ๊ฐ | ๊ณ์ฐ |
์ด ํ๋ ํ์ฅ ํจ์ ํํ์ธ ๊ฐ์ฒด.run { ... }๋ฅผ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค. run { ... }์ฒ๋ผ ๊ฐ์ฒด ์์ด ๋ถ๋ฅด๋ ํ์ค ํจ์๋ ์์ผ๋ฉฐ, ๊ทธ ํํ์๋ ์์ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค.
์ ํ ๊ธฐ์ค:
data class Settings(var width: Int = 0, var height: Int = 0)
// apply: ๊ฐ์ฒด ์ค์ ํ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐํ
val settings = Settings().apply {
width = 800
height = 600
}
// also: ๊ฐ์ ์ ์งํ๋ฉด์ ๋ก๊ทธ ์ถ๋ ฅ
val numbers = listOf(1, 2, 3).also { println("Created: $it") }
// let: nullable ๊ฐ์ด ์์ ๋๋ง ๋ณํ
val name: String? = "Mina"
val length = name?.let { it.length }
// run: ๋ฆฌ์๋ฒ๋ฅผ ์ฌ์ฉํด ๊ณ์ฐ๊ฐ ๋ฐํ
val radius = 50.0
val area = radius.run { PI * this * this }
data class GameCharacter(
var name: String = "",
var health: Int = 100,
var mana: Int = 50,
var position: Vector2 = Vector2(0.0, 0.0),
var level: Int = 1
) {
fun takeDamage(amount: Int) {
health -= amount
}
}
// apply๋ก ์ด๊ธฐํ
val hero = GameCharacter().apply {
name = "Hero"
health = 200
mana = 150
position = Vector2(400.0, 400.0)
level = 5
}
// also๋ก ๊ฒ์ฆ
val validHero = hero.also {
require(it.health > 0) { "Health must be positive" }
println("Hero initialized: ${it.name} at level ${it.level}")
}
data class DataPoint(
val x: Double,
val y: Double,
val value: Double
)
val results = (0 until 1000)
.map { i ->
DataPoint(
x = i.toDouble(),
y = random(100.0),
value = sin(i.toDouble() / 100)
)
}
.also { data ->
println("Generated ${data.size} data points")
}
.filter { it.value > 0 }
.also { data ->
println("Filtered to ${data.size} positive values")
}
.sortedByDescending { it.value }
.also { data ->
println("Top value: ${data.firstOrNull()?.value}")
}
.take(10)
.also { data ->
println("Took top 10: ${data.size} items")
}
program {
var cachedResult: List<Vector2>? = null
extend {
drawer.clear(ColorRGBa.BLACK)
// ์บ์๋ ๊ฒฐ๊ณผ ๋๋ ์๋ก ๊ณ์ฐ
val points = cachedResult?.let { cached ->
println("Using cached result")
cached
} ?: run {
println("Computing new result")
(0 until 20).map { i ->
Vector2(i * 40.0, 300.0 + 100.0 * sin(i.toDouble()))
}
}.also { points ->
cachedResult = points // ์บ์ ์ ์ฅ
}
// ํฌ์ธํธ ๊ทธ๋ฆฌ๊ธฐ
drawer.fill = ColorRGBa.WHITE
points.forEach { circle(it.x, it.y, 5.0) }
}
}
data class DrawingContext(
var strokeColor: ColorRGBa = ColorRGBa.BLACK,
var fillColor: ColorRGBa = ColorRGBa.WHITE,
var strokeWeight: Double = 1.0,
var fontSize: Int = 12
)
fun createContext(init: DrawingContext.() -> Unit): DrawingContext {
return DrawingContext().apply(init)
}
program {
val darkContext = createContext {
strokeColor = ColorRGBa.WHITE
fillColor = ColorRGBa.BLACK
strokeWeight = 2.0
}
val lightContext = createContext {
strokeColor = ColorRGBa.BLACK
fillColor = ColorRGBa.WHITE
strokeWeight = 1.0
}
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.fill = darkContext.fillColor
drawer.stroke = darkContext.strokeColor
drawer.strokeWeight = darkContext.strokeWeight
drawer.circle(200.0, 400.0, 50.0)
}
}
program {
val particles = mutableListOf<Particle>()
val config = object {
var particleCount = 100
var minVelocity = -2.0
var maxVelocity = 2.0
var particleSize = 5.0
}.apply {
particleCount = 150 // ์ค์ ์กฐ์
particleSize = 8.0
}
extend {
drawer.clear(ColorRGBa.BLACK)
// ํํฐํด ์ถ๊ฐ
repeat(3) {
particles.add(
Particle(
position = mouse.position,
velocity = Vector2(
random(config.minVelocity, config.maxVelocity),
random(config.minVelocity, config.maxVelocity)
),
radius = config.particleSize
).also { p ->
println("Particle added with radius: ${p.radius}")
}
)
}
// ํํฐํด ์
๋ฐ์ดํธ ๋ฐ ๋ ๋๋ง
particles
.also { list ->
println("Updating ${list.size} particles")
}
.forEach { p ->
p.update()
p.draw(drawer)
}
particles.removeIf { !it.isAlive }
}
}
์ฌ๋ฌ Scope ํจ์๋ฅผ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.
val result = mutableListOf(1, 2, 3)
.apply {
add(4)
add(5)
}
.also { list ->
println("List: $list")
}
.map { it * 2 }
.let { doubled ->
doubled.sum()
}
println(result) // 30
data class Enemy(var position: Vector2, var health: Int)
object GameManager {
var score = 0
var level = 1
var enemies = mutableListOf<Enemy>()
fun updateScore(points: Int) {
score = (score + points).also { newScore ->
println("Score updated to $newScore")
}
level = score / 1000 + 1
}
fun createEnemies(count: Int) {
enemies = (0 until count)
.map { i ->
Enemy(
position = Vector2(random(800.0), random(600.0)),
health = 10 * level
)
}
.toMutableList()
.also { list ->
println("Created ${list.size} enemies for level $level")
}
}
}
program {
extend {
drawer.clear(ColorRGBa.BLACK)
// ๊ฒ์ ๊ด๋ฆฌ์ ์ํ ํ์
drawer.fill = ColorRGBa.WHITE
drawer.text("Score: ${GameManager.score}", 20.0, 30.0)
drawer.text("Level: ${GameManager.level}", 20.0, 60.0)
drawer.text("Enemies: ${GameManager.enemies.size}", 20.0, 90.0)
}
}
| ์ฅ์ | ์ค๋ช |
|---|---|
| ๊ฐ๊ฒฐ์ฑ | ๋ฐ๋ณต๋๋ ๋ณ์ ์ด๋ฆ ์ ๊ฑฐ |
| ๊ฐ๋ ์ฑ | ์๋๊ฐ ๋ช ํํจ |
| ํํ | ๊ฐ์ฒด ์ค์ ๊ณผ ๊ฐ ๋ณํ์ ๋ธ๋ก์ผ๋ก ๊ตฌ๋ถ |
| ์ ํจ๋ฒ์ | ๋ณ๋์ ๋ณ์ ์ค์ผ ์์ |
| ํํ๋ ฅ | ํจ์ํ ์คํ์ผ๋ก ์ฐ์ํจ |
data class Settings(
var debug: Boolean = false,
var maxConnections: Int = 0
)
// ์ด๊ธฐํ: apply
val config = Settings().apply {
debug = true
maxConnections = 100
}.also { settings ->
println("Config: $settings")
}
// ๊ฒ์ฆ๊ณผ ๊ธฐ๋ก: also
val list = listOf(1, 2, 3).also {
require(it.isNotEmpty())
println("List created")
}
// nullable ๊ฐ ๋ณํ: let
val data: String? = "42"
val transformed = data?.let { it.toInt() }
// ๊ณ์ฐ: run
val radius = 50.0
val area = radius.run { PI * this * this }
์ง๊ธ๊น์ง ๋ฐฐ์ด ์ฝํ๋ฆฐ์ ํต์ฌ ๋ฌธ๋ฒ๋ค:
1. ํ๋ก๊ทธ๋จ ๊ตฌ์กฐ
2. ๋๋ค์ ๋ฆฌ์๋ฒ
3. val/var
4. ๋ฒ์์ ๋ฐ๋ณต
5. ์ปฌ๋ ์
6. Extension ํจ์
7. when ์กฐ๊ฑด ๋ถ๊ธฐ
8. Null ์์ ์ฑ
9. ํด๋์ค์ ๋ฐ์ดํฐ ํด๋์ค
10. Object์ ์ฑ๊ธํด
11. Scope ํจ์ โ
๊ฐ ๋ฌธ๋ฒ์ ์์ ์์ ์์ ๋๋์ง ์์ต๋๋ค. ์ ์ ์์คํ ์ด๋ ๊ฒฉ์ ํจํด์ฒ๋ผ ์ค์ ์ํ์ ๊ทธ๋ฆฌ๊ธฐ ๊ท์น์ ํจ๊ป ๋ค๋ฃจ๋ ์ฝ๋์ ์ ์ฉํ๋ฉด, ์ด๋ค ๋ถ๋ถ์ ๊ณ ์ ํ๊ณ ์ด๋ค ๊ฐ์ ๊ฐฑ์ ํ ์ง ํ๋จํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
data class Shape(
var x: Double = 0.0,
var y: Double = 0.0,
var size: Double = 10.0
)
val shape = Shape().apply {
x = 100.0
y = 200.0
size = 50.0
}
println(shape) // Shape(x=100.0, y=200.0, size=50.0)
val numbers = (1..10).toList()
.also { println("Original: $it") }
.filter { it % 2 == 0 }
.also { println("Filtered: $it") }
// ์ถ๋ ฅ:
// Original: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Filtered: [2, 4, 6, 8, 10]
program {
var selected: Vector2? = Vector2(100.0, 120.0)
extend {
drawer.clear(ColorRGBa.BLACK)
selected?.let { pos ->
drawer.fill = ColorRGBa.CYAN
drawer.circle(pos.x, pos.y, 20.0)
}
// selected = null๋ก ๋ฐ๊พธ๋ฉด ์์ ๊ทธ๋ ค์ง์ง ์์ต๋๋ค.
}
}
data class Circle(val radius: Double)
val circle = Circle(50.0)
val area = circle.run {
PI * radius * radius
}
println(area) // 7853.981633974483
๋ง์ฐ์ค๋ฅผ ๋๋ฅด๋ฉด ํ์ฌ ์์น์ ์
์๋ฅผ ์ต๋ ๋ค์ฏ ๊ฐ ์ถ๊ฐํฉ๋๋ค. apply๋ก ์ค์ ์ ๋ง๋ค๊ณ , also๋ก ์์ฑ ์์ ์ ๊ธฐ๋กํ๋ฉฐ, let์ผ๋ก ๋ง์ง๋ง ์ ํ ์์น๋ฅผ ํ์ํฉ๋๋ค. ๋๋ฅด๊ณ ์๋ ๋์ ๊ฐ์ ์
๋ ฅ์ ๋ฐ๋ณต ์ฒ๋ฆฌํ์ง ์๋๋ก ํ๋ ์ ์ฌ์ด์ ๋ฒํผ ์ํ๋ฅผ ๋น๊ตํฉ๋๋ค.
data class Particle(
var position: Vector2,
var velocity: Vector2,
val radius: Double,
val lifespan: Double,
var age: Double = 0.0
) {
val isAlive: Boolean get() = age < lifespan
fun update() {
position += velocity
age += 1.0
}
fun draw(drawer: Drawer) {
val alpha = (1.0 - age / lifespan).coerceIn(0.0, 1.0)
drawer.fill = ColorRGBa(1.0, 1.0, 1.0, alpha)
drawer.circle(position.x, position.y, radius)
}
}
program {
data class Config(var particleLimit: Int = 100, var particleSize: Double = 5.0)
val config = Config().apply {
particleLimit = 200
particleSize = 8.0
}
val particles = mutableListOf<Particle>()
var selectedPosition: Vector2? = null
var wasMouseDown = false
extend {
drawer.clear(ColorRGBa.BLACK)
val mouseDown = mouse.buttonDown
if (mouseDown && !wasMouseDown) {
selectedPosition = mouse.position
val remaining = (config.particleLimit - particles.size).coerceAtLeast(0)
repeat(minOf(5, remaining)) {
particles.add(
Particle(
position = mouse.position,
velocity = Vector2(random(-2.0, 2.0), random(-2.0, 2.0)),
radius = config.particleSize,
lifespan = 60.0
).also { particle ->
println("Particle created at ${particle.position}")
}
)
}
}
wasMouseDown = mouseDown
particles.forEach { it.update() }
particles.removeIf { !it.isAlive }
particles.forEach { it.draw(drawer) }
selectedPosition?.let { position ->
drawer.stroke = ColorRGBa.YELLOW
drawer.circle(position.x, position.y, 14.0)
}
}
}
ํ ๋ฒ ๋๋ฅผ ๋๋ง๋ค ์
์ ๋ค์ฏ ๊ฐ๊ฐ ์ถ๊ฐ๋๊ณ , ์ ์ฒด ๊ฐ์๋ 200๊ฐ๋ฅผ ๋์ง ์์ต๋๋ค. ์์ฑ ๋ก๊ทธ๋ ๋ง์ฐ์ค๋ฅผ ๋๋ฅด๊ธฐ ์์ํ ์๊ฐ์๋ง ์ถ๋ ฅ๋ฉ๋๋ค. selectedPosition์ด ์์ง ์ ํด์ง์ง ์์๋ค๋ฉด let ๋ธ๋ก์ ์คํ๋์ง ์์ผ๋ฉฐ, ํ ๋ฒ์ด๋ผ๋ ๋๋ฅธ ๋ค์๋ ๋ง์ง๋ง ๋๋ฅธ ์์น์ ๋
ธ๋ ์์ด ํ์๋ฉ๋๋ค.
Scope ํจ์๋ ๋ฆฌ์๋ฒ์ ๋ฐํ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ตฌ๋ถํ๋ฉด ์ ํ์ด ๋จ์ํด์ง๋๋ค.
๊ธฐ์ตํ ๊ธฐ์ค:
applyalsoletrun์ด ๋ค ๊ฐ์ง๋ฅผ ๊ธฐ์ตํ๋ฉด ๋ฉ๋๋ค.
์ด ๋ฌธ์๊น์ง 0~11๋ฒ์์ ๋ค๋ฃฌ Kotlin ๋ฌธ๋ฒ์ ์ดํด๋ดค์ต๋๋ค. ๋ค์ ๋จ๊ณ์์๋ ์ด ๋ฌธ๋ฒ์ ์์ OPENRNDR ์ํ์ ์ ์ฉํ๋ฉฐ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ฅ์ ์ตํ๋ฉด ๋ฉ๋๋ค.