Study/다재다능 코틀린 프로그래밍
Day 4. 외부 반복과 아규먼트 매칭
주지민
2021. 10. 27. 00:05
반응형
본 포스트는 지인들과 스터디한 내용을 정리한 포스트입니다
http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9788931463422
1. 외부 반복과 아규먼트 매칭
- 코틀린은 명령형 스타일에서 사용되는 외부 반복자와 함수형 스타일에서 사용되는 내부 반복자 모두 제공
- 현재 챕터에서는 외부 반복의 효율성에 대해서 집중
- kotlin.ranges 패키지는 반복을 편하게 해주는 심플한 코드를 제공
- 레인지 클래스
- 범위의 첫 번째 값을 쓰고 '..'연산자를 붙이고 범위의 마지막 값을 적으면 된다
- range는 연산자의 앞, 뒤 두 값 모두를 포함한다
- 예제 코드
val oneToFive: IntRange = 1..5 val aToE: CharRange = 'a'..'e' val seekHelp: ClosedRange<String> = "hell".."help"
- 정방향 반복
- for(x in ..) 문법을 통해 생성된 범위안에서 반복을 수행할 수 있다 ( 오름차순으로 진행되는 반복 )
- 예제 코드
// ranges.kts for (i in 1..5) { print("$i, ") // 1,2,3,4,5, }
- 명시적으로 선언하지 않아도 'i'는 val이다 ( 이뮤터블 ), 또한 반복문 안으로 스코프가 제한된다
- 위처럼 외부 반복을 하기위한 조건은 생성된 범위 객체가 iterator() 함수가 있어야한다
- IntRange, CharRange 같은 클래스는 iterator() 함수(연산자)가 존재
- ClosedRange에는 iterator() 함수가 존재하지 않는다
error: for-loop range must have an 'iterator()' method
- 후방향 반복
- 내림차순으로 진행되는 반복
- "5..1"과 같은 형태로 만들면 되지 않을까 생각할 수 있지만 아쉽게도 .downTo() 메서드를 사용하여 내림차순을 나타줘야한다
- 예제코드
// reverse.kts for (i in 5.downTo(1)) { print("$i, ") // 5,4,3,2,1, } for (i in 5 downTo 1) { print("$i, ") // 5,4,3,2,1, }
- 시작값.downTo(끝값) => 시작값을 포함하여 끝값을 포함한 값까지 내림차순으로 반복
- 시작값 downTo 끝값 => 훨씬더 간략하게 표현할 수 있다
- 범위 안의 값 건너뛰기
- 지금까지는 순차적인 값의 증가, 값의 감소를 반복시켰지만 범위 안에서 특정 값을 건너뛰는 방법을 소개한다
- until() 메서드
- 숫자 범위를 반복할 때 마지막 값을 건너뜀 ( 마지막 값을 포함하지 않음 )
- downTo처럼 .메서드 로 표현할 수 있지만 간결하게 .과 괄호를 버릴 수 있다
- 예제코드
// skipvalues.kts for (i in 1.until(5)) { print("$i, ") // 1,2,3,4, } for (i in 1 until 5) { print("$i, ") // 1,2,3,4, }
- step() 메서드
- 반복 중에 특정 값을 건너뛸때 사용
- "..", "until", "downTo" 등으로 만들어진 IntRange, IntProgression 객체를 IntProgression 객체로 변화시킨다
- IntProgression 객체는 일부 값을 건너 뛴다
- 예제코드
// skipvalues.kts for (i in 1 until 10 step 3) { print("$i, ") // 1, 4, 7 }
- filter() 메서드
- step() 메서드가 순차적인 방법으로 값을 건너뛴 함수라면 filter() 메서드는 값을 건너뛸 조건 자체를 만드는 함수이다
- 예제코드
// skipvalues.kts // case1: simple case for (i in (1..9).filter { it % 3 == 0 || it % 5 == 0 }) { print("$i, ") // 3, 5, 6, 9 } // case2: Using lambda val myCondition = { it: Int -> it % 3 == 0 } for (i in (1..5).filter(myCondition)) { print("$i, ") }
2. 배열과 리스트의 반복
- 코틀린에서는 특별한 조치 없이 JDK의 콜렉션 클래스와 인터페이스를 바로 사용할 수 있다
- 예제코드 ( 배열 생성 )
// iterate.kts val array = arrayOf(1,2,3)
- 배열을 만들기위해 arrayOf() 메서드 사용
- kotlin 패키지에 포함된 함수는 굳이 kotlin.arrayOf()라고 적거나 kotlin을 임포트할 필요없이 사용할 수 있다
- primitive type의 배열로 만들려면 type(int 등) prefix를 가진 intArrayOf(...) 메서드를 사용하면 된다
- 예제코드 ( 리스트 컬렉션 생성 )
// iterate.kts val list = listOf(1,2,3) println(list.javaClass) // class java.util.Arrays$ArrayList for (e in list) { print("$e, ") // 1, 2, 3, }
- 콜렉션의 값을 이용하여 출력한 형태이다
- list 안의 인덱스를 찾고 싶다면 indices 속성을 사용하면 된다
- 예제 코드
// index.kts var names = listOf("Tom", "jerry", "Spike") for (index in names.indices) { println("Position of ${names.get(index)} is $index") } //Position of Tom is 0 //Position of jerry is 1 //Position of Spike is 2 for ((index, name) in names.withIndex()) { println("Position of $name is $index") }
- withIndex() 메서드를 통해 인덱스와 값 둘 다 한꺼번에 가져올 수도 있다
3. when을 사용해야 할 때
- 코틀린에는 switch문이 없는 대신 when이 있다
- 표현식으로서의 when
- 예제코드
// when.kts fun beforeIsAlive(alive: Boolean, numberOfLiveNeighbors: Int): Boolean { if (numberOfLiveNeighbors < 2) { return false } if (numberOfLiveNeighbors > 3) { return false } if (numberOfLiveNeighbors == 3) { return true } return alive && numberOfLiveNeighbors == 2 } fun isAlive(alive: Boolean, numberOfLiveNeighbors: Int) = when { numberOfLiveNeighbors < 2 -> false numberOfLiveNeighbors > 3 -> false numberOfLiveNeighbors == 3 -> true else -> alive && numberOfLiveNeighbors == 2 }
- beforeIsAlive 메서드를 살펴보면 전통적으로 사용하던 if-else문의 조합으로 구성되어 있다, 지저분하고 장황하며 오류를 유발한다
- when을 이용한 isAlive 메서드는 리턴타입을 타입추론을 통해 이용하게 하고 단일 표현식 함수 문법을 사용했다
- 즉 함수에 의해서 리턴되는 값은 when 안의 하나의 표현식에서 나온 값이다
- when에 값이나 표현식을 전달
- 예제코드
// activity.kts fun whatToDo(dayOfWeek: Any) = when (dayOfWeek) { "Saturday", "Sunday" -> "Relax" in listOf("Monday", "TuesDay", "Wednesday", "Thursday") -> "Work hard" in 2..4 -> "Work hard" "Fridy" -> "Party" is String -> "What?" else -> "No clue" } println(whatToDo("Sunday")) // Relax println(whatToDo("Wednesday")) // Work hard
- 위처럼 when 파라미터로 값을 전달하여 심플하게 구성할 수 있다
- 각 case에는 두 개 이상의 값을 사용하는 것이 허용된다
- 코틀린 컴파일러는 when에서 else가 마지막이 아닌 부분에 오는 것을 허용하지 않는다
- 예제코드
- 예제코드
- 명령문으로써의 when
- 하나 이상의 값에 기반해서 다른 동작을 원한다면 when을 표현식이 아니라 명령문으로 사용하면 된다
- 예제코드
// activity.kts fun whatToDo(dayOfWeek: Any) { when (dayOfWeek) { "Saturday", "Sunday" -> println("Relax") in listOf("Monday", "TuesDay", "Wednesday", "Thursday") -> println("Work hard") in 2..4 -> println("Work hard") "Fridy" -> println("Party") is String -> println("What?") else -> println("No clue") } } whatToDo("Sunday") whatToDo("Wednesday") whatToDo(3)
- 해당 함수 whatToDo()의 리턴타입은 Unit이다, 아무것도 리턴하지 않고 println()만 호출
- when과 변수의 스코프
- 이전 예제들에서 변수는 when 명령문 혹은 표현식의 외부에서 전달받아 매칭을 위해서만 사용되었다
- 매칭에 사용되는 변수는 when의 스코프만으로 제한되어있다
- 예제코드: 전통적인 방식의 장황한 코드
// cores.kts fun systemInfo(): String { val numberOfCores = Runtime.getRuntime().availableProcessors() return when (numberOfCores) { 1 -> "1 core, packing this one to the museum" in 2..16 -> "You have $numberOfCores cores" else -> "$numberOfCores cores!, I want your machine" } }
- val numberOfCores 는 결국 when 스코프안에서만 쓰이는 변수이다
- 예제코드: when 파라미터로 전달
// cores.kts fun systemInfo(): String = when (val numberOfCores = Runtime.getRuntime().availableProcessors()) { 1 -> "1 core, packing this one to the museum" in 2..16 -> "You have $numberOfCores cores" else -> "$numberOfCores cores!, I want your machine" } println(systemInfo())
- when 파라미터로 해당 블록안에서만 사용할 변수를 선언 및 초기화해줬다
- when의 결과를 바로 리턴하여 systemInfo() 메서드를 감싸고있던 {} 블록과 return 키워드가 없어졌다
728x90
반응형