Kotlin Koans Workshop - I. introduction

이미지 출처: https://kotlinlang.org/assets/images/open-graph/kotlin_250x250.png

테스트케이스로 코틀린 문법익히기

Chapter1 - 주요기능 소개

Kotlin Github repository의 kotlin-koans 프로젝트를 기반으로 포스팅 되었음을 밝힘니다.
출처: https://github.com/Kotlin/kotlin-koans

목차

표현식으로 문자열 리턴하기 목차 ⇈

src package

1
2
3
4
5
6
7
// kotlin function에서는 리턴값을 표현식으로 선언할 수 있습니다.
fun task0() = "OK"

// java의 메서드와 유사하게 표현하면 다음과 같습니다.
fun task0(): String {
return "OK"
}

test package

1
2
3
4
5
6
// task0 function의 리턴값으로 문자열 "OK"가 리턴되면 성공하는 케이스입니다.
class N00StartKtTest {
@Test fun testOk() {
assertEquals("OK", task0())
}
}

Java코드를 Kotlin코드로 변환하기 목차 ⇈

src package(Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//  IntelliJ IDEA 또는 Android Studio를 사용하는 경우 Java코드를 Kotlin코드로 변환 할 수 있습니다.   
// .java 파일을 통째로 .kt 파일로 바꿀수도 있고, copy & paste만으로도 변환이 가능합니다.
// 아래 task1 메서드를 복사해서 IntelliJ IDEA 또는 Android Studio의 편집기의 .kt파일에 붙여 넣으면 자동으로 코드가 변환됩니다.
public String task1(Collection<Integer> collection) {
StringBuilder sb = new StringBuilder();
sb.append("{");
Iterator<Integer> iterator = collection.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
sb.append(element);
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append("}");
return sb.toString();
}

src package(Kotlin)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Kotlin 문법으로 변경된 function은 아래와 같습니다.
fun task1(collection: Collection<Int>): String {
val sb = StringBuilder()
sb.append("{")
val iterator = collection.iterator()
while (iterator.hasNext()) {
val element = iterator.next()
sb.append(element)
if (iterator.hasNext()) {
sb.append(", ")
}
}
sb.append("}")
return sb.toString()
}

test package

1
2
3
4
5
6
7
// 배열의 정수아이템을 문자열로 변경하고 해당값을 비교하는 케이스입니다.
// 이번 예제의 목적은 이미구현된 코드를 IDEA를 이용하여 변환하는 것이 목적입니다.
class N01JavaToKotlinConverterKtTest {
@Test fun collection() {
assertEquals("{1, 2, 3, 42, 555}", task1(listOf(1, 2, 3, 42, 555)))
}
}

joinToString함수로 prefix와 postfix 붙이기 목차 ⇈

src package

1
2
3
4
// 아래와 같이 Kotlin collection에서 제공하는 joinToString 함수를 이용하여 prefix와 postfix를 붙일수 있습니다.
fun task2(collection: Collection<Int>): String {
return collection.joinToString(prefix = "{", postfix = "}")
}

test package

1
2
3
4
5
6
// 문자열의 시작과 끝에 특정 문자를 조합하는 케이스입니다.
class N02NamedArgumentsKtTest {
@org.junit.Test fun testJoinToString() {
assertEquals("{1, 2, 3, 42, 555}", task2(listOf(1, 2, 3, 42, 555)))
}
}

default arguments 선언하기 목차 ⇈

src package(Kotlin)

1
2
3
4
5
6
7
8
9
10
// default argument를 함수의 선언부에 정의해서 함수 호출시 전달되지 않는값에 대해 자동으로 기본값을 할당합니다.
fun foo(name: String, number: Int = 42, toUpperCase: Boolean = false) =
(if (toUpperCase) name.toUpperCase() else name) + number

fun task3(): String {
return (foo("a") +
foo("b", number = 1) +
foo("c", toUpperCase = true) +
foo(name = "d", number = 2, toUpperCase = true))
}

src package(Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Kotlin 코드를 Java코드로 표현하면 아래와 같습니다.
private int defaultNumber = 42;

public String foo(String name, int number, boolean toUpperCase) {
return (toUpperCase ? name.toUpperCase() : name) + number;
}

public String foo(String name, int number) {
return foo(name, number, false);
}

public String foo(String name, boolean toUpperCase) {
return foo(name, defaultNumber, toUpperCase);
}

public String foo(String name) {
return foo(name, defaultNumber);
}

test package

1
2
3
@Test fun testDefaultAndNamedParams() {
assertEquals("a42b1C42D2", task3())
}

람다식 이용하기 목차 ⇈

src package

1
2
3
// 람다식을 이용하여 loop문을 직접적으로 사용하지 않고 배열을 순회할 수 있습니다.   
// 아래 function에 사용되는 any함수의 경우 람다식 안의 결과가 1건이라도 true이면 true를 리턴합니다.
fun task4(collection: Collection<Int>) = collection.any { element -> element % 2 == 0 }

test package

1
2
3
4
5
6
7
@Test fun contains() {
assertTrue(task4(listOf(1, 2, 3)))
}

@Test fun notContains() {
assertFalse(task4(listOf(1, 3, 5)))
}

String 템플릿 사용하기 목차 ⇈

src package

1
2
3
4
// Kotlin에서는 dollar sign($)을 이용하여 문자열선언과 함게 변수를 정의할 수 있습니다.   
// 아래처럼 task5 function을 정의하면 호출시 """\d{2} (JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC) \d{4}""" 문자열이 리턴됩니다.
val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"
fun task5(): String = """\d{2} $month \d{4}"""

test package

1
2
3
4
5
6
7
8
9
10
11
@Test fun match() {
assertTrue("11 MAR 1952".matches(task5().toRegex()))
}

@Test fun match1() {
assertTrue("24 AUG 1957".matches(task5().toRegex()))
}

@Test fun doNotMatch() {
assertFalse("24 RRR 1957".matches(task5().toRegex()))
}

data class 사용하기 목차 ⇈

src package

1
2
3
4
5
6
// class 선언시에 'data' modifier를 추가하면 toString() function을 이용하여 객체의 내용을 출력할 수 있습니다.
data class Person(val name: String, val age: Int)

fun task6(): List<Person> {
return listOf(Person("Alice", 29), Person("Bob", 31))
}

test package

1
2
3
@Test fun testListOfPeople() {
assertEquals("[Person(name=Alice, age=29), Person(name=Bob, age=31)]", task6().toString())
}

nullable type 이용하기 목차 ⇈

src package

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun sendMessageToClient(
client: Client?, message: String?, mailer: Mailer
) {
// 자료형 뒤에 safe call operator(?)를 붙이면 null값을 할당할 수 있고 safe call을 이용하여 NPE을 방지할 수 있습니다.
// email 상수에 값을 할당할때 safe call을 이용하면 다음과 같이 동작합니다.
// client가 null이 아니면 personalInfo속성에 접근
// personalInfo가 null이 아니면 email값을 할당
val email: String? = client?.personalInfo?.email
if (email != null && message != null) {
mailer.sendMessage(email, message)
}
}

class Client (val personalInfo: PersonalInfo?)
class PersonalInfo (val email: String?)

interface Mailer {
fun sendMessage(email: String, message: String)
}

test package

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
fun testSendMessageToClient(
client: Client?,
message: String?,
email: String? = null,
shouldBeInvoked: Boolean = false
) {
var invoked = false
sendMessageToClient(client, message, object : Mailer {
override fun sendMessage(actualEmail: String, actualMessage: String) {
invoked = true
assertEquals("The message is not as expected:",
message, actualMessage)
assertEquals("The email is not as expected:",
email, actualEmail)
}
})
assertEquals("The function 'sendMessage' should${if (shouldBeInvoked) "" else "n't"} be invoked",
shouldBeInvoked, invoked)
}

@Test fun everythingIsOk() {
testSendMessageToClient(Client(PersonalInfo("bob@gmail.com")),
"Hi Bob! We have an awesome proposition for you...",
"bob@gmail.com",
true)
}

@Test fun noMessage() {
testSendMessageToClient(Client(PersonalInfo("bob@gmail.com")), null)
}

@Test fun noEmail() {
testSendMessageToClient(Client(PersonalInfo(null)), "Hi Bob! We have an awesome proposition for you...")
}

@Test fun noPersonalInfo() {
testSendMessageToClient(Client(null), "Hi Bob! We have an awesome proposition for you...")
}

@Test fun noClient() {
testSendMessageToClient(null, "Hi Bob! We have an awesome proposition for you...")
}

smart cast 이용하기 목차 ⇈

src package

1
2
3
4
5
6
7
8
9
10
11
// 조상클래스가 동일한경우 type을 조건으로 when표현식을 사용할 수 있습니다.   
// 조건에 따라 분기된 람다식에서 추가적인 캐스팅절차없이 원래의 자료형을 곧바로 사용할 수 있습니다.
sealed class Expr
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()

fun eval(e: Expr): Int =
when (e) {
is Num -> e.value
is Sum -> eval(e.left) + eval(e.right)
}

test package

1
2
3
4
5
6
7
8
9
10
11
@Test fun testNum() {
assertEquals("'eval' on Num should work:", 2, eval(Num(2)))
}

@Test fun testSum() {
assertEquals("'eval' on Sum should work:", 3, eval(Sum(Num(2), Num(1))))
}

@Test fun testRecursion() {
assertEquals("'eval' should work recursively:", 6, eval(Sum(Sum(Num(1), Num(2)), Num(3))))
}

함수 확장하기 목차 ⇈

src package

1
2
3
4
5
// Kotlin에서는 기존 클래스의 function을 확작하여 사용할 수 있습니다.
data class RationalNumber(val numerator: Int, val denominator: Int)

fun Int.r(): RationalNumber = RationalNumber(this, 1)
fun Pair<Int, Int>.r(): RationalNumber = RationalNumber(this.first, this.second)

test package

1
2
3
4
5
6
7
@Test fun testIntExtension() {
assertEquals("Rational number creation error: ", RationalNumber(4, 1), 4.r())
}

@Test fun testPairExtension() {
assertEquals("Rational number creation error: ", RationalNumber(2, 3), Pair(2, 3).r())
}

객체 표현식 이용하기 목차 ⇈

src package

1
2
3
4
5
6
7
8
9
// 객체 표현식을 이용하여 객체를 생성 할 수 있습니다.   
// 아래와 같이 객체 표현식을 이용하여 abstract메서드를 구현하면서 객체를 생성 할 수 있습니다.
fun task10(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
Collections.sort(arrayList, object : Comparator<Int> {
override fun compare(x: Int, y: Int) = y - x
})
return arrayList
}

test package

1
2
3
@Test fun testSort() {
assertEquals(listOf(5, 2, 1), task10())
}

SAM(Single Abstract Method) 구현하기 목차 ⇈

src package

1
2
3
4
5
6
// 하나의 abstract method를 가지고 있는 클래스를 구현해야 하는 경웅 람다식을 이용하여 간단하게 정의 할 수도 있습니다.
fun task11(): List<Int> {
val arrayList = arrayListOf(1, 5, 2)
Collections.sort(arrayList, { x, y -> y - x })
return arrayList
}

test package

1
2
3
@Test fun testSort() {
assertEquals(listOf(5, 2, 1), task11())
}

콜렉션 확장기능 이용하기 목차 ⇈

src package

1
2
3
4
5
// Kotlin 표준 라이브러리에는 컬렉션 작업을 보다 편리하게 해주는 많은 확장 기능이 포함되어 있습니다.   
// 'sortedDescending'을 아래와 같이 사용할 경우 별도로 Comparator를 구현하지 않아도 됩니다.
fun task12(): List<Int> {
return arrayListOf(1, 5, 2).sortedDescending()
}

test package

1
2
3
@Test fun testSort() {
assertEquals(listOf(5, 2, 1), task12())
}

Table of contents


Open source project on GitHub


Jupyter/IPython Notebook


Open API


NoSQL


Jekyll


Gradle


Kotlin


C++

  • C++ keywords
  • 윤성우 열혈강의 C++ 프로그래밍 예제코드 [펼치기]
    1. C언어 기반의 C++ 1
      • printf와 scanf를 대신하는 입출력 방식
      • 함수 오버로딩(Function Overloading)
      • 매개변수의 디폴트 값(Default Value)
      • 인라인 함수(Inline)함수
      • 이름공간(namespace)에 대한 소개
    2. C언어 기반의 C++ 2
      • 새로운 자료형 bool
      • 참조자(Reference)의 이해
      • 참조자(Reference)와 함수
      • maloc & free를 대신하는 new & delete
      • C++에서 C언어의 표준함수 호출하기
    3. 클래스의 기본
      • C++에서의 구조체
      • 클래스(Class)와 객체(Object)
      • 객체지향 프로그래밍의 이해
    4. 클래스의 완성
      • 정보은닉(Information Hiding)
      • 캡슐화(Encapsulation)
      • 생성자(Constructor)와 소멸자(Destructor)
      • 클래스와 배열 그리고 this 포인터
    5. 복사 생성자
      • ‘복사 생성자’ 와의 첫 만남
      • ‘깊은 복사’와 ‘얕은 복사’
      • 복사 생성자의 호출시점
    6. friend와 static 그리고 const
      • const와 관련해서 아직 못다한 이야기
      • 클래스와 함수에 대한 friend 선언
      • C++에서의 static
    7. 상속(Inheritance)의 이해
      • 상속에 들어가기에 앞서
      • 상속의 문법적인 이해
      • protected 선언과 세 가지 형태의 상속
      • 상속을 위한 조건
    8. 상속과 다형성
      • 객체 포인터의 참조관계
      • 가상함수(Vitual Function)
      • 가상 소멸자와 참조자의 참조 가능성
    9. 가상(Virtual)의 원리와 다중상속
      • 멤버함수와 가상함수의 동작원리
      • 다중상속(Multiple Inheritance)에 대한 이해
    10. 연산자 오버로딩 1
      • 연산자 오버로딩의 이해와 유형
      • 단항 연산자의 오버로딩의
      • 교환법칙 문제의 해결
      • cout, cin 그리고 endl의 정체
    11. 연산자 오버로딩 2
      • 반드시 해야 하는 대입 연산자의 오버로딩
      • 배열의 인덱스 연산자 오버로딩
      • 그 이외의 연산자 오버로딩
    12. String 클래스의 디자인
      • C++ 표준과 표즌 string 클래스
      • 문자열 처리 클래스의 정의
    13. 템플릿(Template) 1
      • 템플릿(Template)에 대한 이해와 함수 템플릿
      • 클래스 템플릿(Class Temlpate)
    14. 템플릿(Template) 2
      • Chapter 13에서 공부한 내용의 확장
      • 클래스 템플릿의 특수화(Class Temlpate Specialization)
      • 템플릿의 인자
      • 템플릿과 static
    15. 예외처리(Exception Handling)
      • 예외상황과 예외처리의 이해
      • C++의 예외처리 메커니즘
      • Stack Unwinding(스택 풀기)
      • 예외상황을 표현하는 예외 클래스의 설계
      • 예외처리와 관련된 또 다른 특성들
    16. C++의 형 변환 연산자
      • C++에서의 형 변환 연산

ETC