•
문(Statement) vs 함수(function)
◦
문(Statement)은 하나 이상의 기계어 명령어 (Instruction)로 치환
◦
반복문(Iteration Statement)은 코드 중복을 제거
# Expression
println(5)
println(4)
println(3)
println(2)
println(1)
# Iteration Statement
for (x in 5 downTo 1) {
println(n)
}
JavaScript
복사
◦
함수 선언(function)은 문을 메모리 주소로 치환후 표현식으로 호출함으로써 재사용성을 높힘
# Function Declaration
fun sequencePrinter(num: Long) {
for (x in 5 downTo 1) {
println(n)
}
}
JavaScript
복사
◦
반복문(Statement)은 순회 가능한(Iterable)한 ‘집합’과 이에 적용할 ‘연산’이 결합됨
for oddSequencePrinter(num: Long) {
for (x in 5 down To 1) {
if (x % 2 == 1) {
println(n)
}
}
}
JavaScript
복사
◦
반복문(Statment)을 표현식(Expression)으로 치환
# Expression
fun numberGenerator () {
val numbers = listOf(1, 2, 3, 4, 5)
val listIterator = numbers.listIterator())
while (listIterator.hasNext()) {
val num = listIterator.next()
yield num
}
}
(-(1..5)).filter { x -> x % 2 != 0 }.foreach { println(it) }
JavaScript
복사
•
이터레이터를 사용하는 이유
◦
(반복)문의 표현식 (이터레이터와 시퀀스) 치환
◦
집합과 연산의 분리
▪
집합에 대한 연산을 따로 처리할 수 있음
▪
Composition을 통해 재활용성을 높힐 수 있음
▪
게으른(Lazy) 연산 가능 (Iterator [x], Sequence [o])
(-(1..5)).filter { x -> x % 2 != 0 }.forEach { println(it) }
JavaScript
복사
◦
언어 차원의 이터레이터 지원
public interface Iterator<out T> {
public operator fun next(): T
public operator fun hasNext(): Boolean
}
val iterator: Iterator<Any> = iterator {
yield(5)
yield(4)
yield(3)
yield(2)
yield(1)
}
iterator.forEach {
println(it)
}
JavaScript
복사
•
시퀀스를 사용하는 이유
◦
이터레이터의 한계: Lazy Evaluation을 지원하지 않음
◦
시퀀스(Stream) : 이터레이터 (Iterator) + Lazy Evaluation + Cursor
val iter = iterator {
yield(5)
yield(4)
yield(3)
yield(2)
yield(1)
}
while (iter.hasNext()) {
println(iter.next())
}
val eagor = listOf(5, 4, 3, 2, 1)
println("before sum ")
val eagorSum: List<Int> = eagor.map { print("$it "); it * it }
println(eagorSum.sum())
val lazy = sequence {
yield(5)
yield(4)
yield(3)
yield(2)
yield(1)
}.map {
println("$it "); it * it
}
println("before sum ")
val lazySum = lazy.sum() // terminal
println(lazySum)
JavaScript
복사
•
프로듀서 - 컨슈머를 사용하는 이유
◦
순회 중 중단 재개 가능 (suspend / resume)
▪
iterator와 sequence는 중단점 없이 순차 실행
◦
생산과 소비의 주체 및 시점이 달라지므로, lazily consume 가능
▪
Invocation과 Execution의 분리
◦
프로듀서 생산 - 소비
val context = newSingleThreadContext("myThread")
val producer = GlobalScope.produce(context) {
for (i in 0..9) {
send(i)
}
}
producer.consumeEach {
println(it)
}
JavaScript
복사
◦
채널 메시지 생산 - 소비
val channel = Channel<Int>()
val sender = GlobalScope.launch {
for (i in 0..9) {
channel.send(i)
}
}
while(!channel.isClosedForReceive && !channel.isEmpty) {
println(channel.receive())
}
JavaScript
복사
•
활용예
override fun onCreate(savedInstanceState: Bundle?) {
...
GlobalScope.launch {
loadMore()
}
}
JavaScript
복사
override suspend fun loadMore() {
val producer = ArticleProducer.producer
if (!producer.isClosedForReceive) {
val articles = producer.receive()
GlobalScope.launch(Dispatchers.Main) {
findViewById<ProgressBar>(R.id.progressBar).visibility = View.GONE
viewAdapter.add(articles)
Log.d("Main", "Currently has ${viewAdapter.itemCount} articles")
}
}
}
JavaScript
복사
interface ArticleLoader {
suspend fun loadMore()
}
class ArticleAdapter(private val loader: ArticleLoader)
: RecyclerView.Adapter<ArticleAdapter.ViewHolder>() {
private val articles: MutableList<Article> = mutableListOf()
private var loading = false
class ViewHolder(val layout: LinearLayout,
val feed: TextView,
val title: TextView,
val summary: TextView
) : RecyclerView.ViewHolder(layout)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): ViewHolder {
val layout = LayoutInflater.from(parent.context)
.inflate(R.layout.article, parent, false) as LinearLayout
val feed = layout.findViewById<TextView>(R.id.feed)
val title = layout.findViewById<TextView>(R.id.title)
val summary = layout.findViewById<TextView>(R.id.summary)
return ViewHolder(layout, feed, title, summary)
}
override fun getItemCount(): Int {
return articles.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val article = articles[position]
// request more articles when needed
if (!loading && position >= articles.size - 2) {
loading = true
GlobalScope.launch {
loader.loadMore()
loading = false
}
}
holder.feed.text = article.feed
holder.title.text = article.title
holder.summary.text = article.summary
}
fun add(articles: List<Article>) {
this.articles.addAll(articles)
notifyDataSetChanged()
}
}
JavaScript
복사