<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sonsation.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sonsation.github.io/" rel="alternate" type="text/html" /><updated>2025-11-04T12:07:08+00:00</updated><id>https://sonsation.github.io/feed.xml</id><title type="html">Site Title</title><subtitle>An amazing website.</subtitle><author><name>Your Name</name></author><entry><title type="html">html &amp;amp; css 기본정리</title><link href="https://sonsation.github.io/web/html/" rel="alternate" type="text/html" title="html &amp;amp; css 기본정리" /><published>2019-09-29T04:49:28+00:00</published><updated>2019-09-29T04:49:28+00:00</updated><id>https://sonsation.github.io/web/html</id><content type="html" xml:base="https://sonsation.github.io/web/html/"><![CDATA[<h1 id="1-header-body-footer-역할-및-선언방법">1. header, body, footer 역할 및 선언방법</h1>

<h2 id="header">header</h2>
<p>웹 사이트 이름, 글로벌 링크(로그인, 회원가입, 사이트맵,언어 선택등 웹사이트 어느 곳에서든지 이용할 수 있는 링크)등으로 구성된 영역이다.
브라우저가 헤더영역을 인식할 수 있게되면 스크린리더의 내비게이션과 검색엔진의 색인에 도움을 줄 수 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;header&gt;</span>
  <span class="nt">&lt;h1&gt;</span>LOGO<span class="nt">&lt;/h1&gt;</span>
  <span class="nt">&lt;h2&gt;</span>검색<span class="nt">&lt;/h2&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/header&gt;</span>
</code></pre></div></div>

<h2 id="body">body</h2>
<body> 요소는 문서의 본문 영역을 표시한다. 본문 영역은 실제 콘텐츠가 표현되는 공간이며, 이 공간에서 사용자와의 상호작용이 실질적으로 이루어진다. 또한 body요소는 브라우저가 렌더링해야 할 범위를 알려준다.
따로 작성된 css나 javascript 파일이 외부적으로 선언되는 구역이다.

```markdown
<body>
  <div class="custom">
    element body
  </div>
</body>
```

## footer
웹 문서 맨 아래쪽에 있으며 저작권, 연락처등으로 구성된 영역이다.

```markdown
<footer>
  <address>
    연락처 : <a href="mailto:sonsation@sonsation.com">help</a>
  </address>
  <small>Copyright</small>
</footer>
```

# 2. div, span
<div>와 <span> 태그는 영역을 설정할때 사용된다. div는 줄 바꿈이 되지만 span은 옆으로 붙는다. 
 텍스트를 표현할 때 블럭 요소인 div는 사각형 박스로 구역을 정하기 때문에 레이아웃을 잡는 용도로 사용되며, 인라인 요소인 span은 문장 단위로 사용되기 때문에 텍스트의 속성을 지정할 때 사용된다고 생각한다.
  
## 기본적으로 사용하는 css 속성
```markdown
.custom {
  height: 1024px;
  width: 1920px;
  background: red;
  background: url('image url');
  background-size: auto|length|cover|contain|initial|inherit;
  background-position: value;
  background-repeat: repeat|repeat-x|repeat-y|no-repeat|initial|inherit
}
```

# 3.id, class
class는 여러개를 사용할 수 있지만 id는 고유성을 가지므로 한 문서에 한번만 사용할 수 있다.
홈페이지 전체적인 스타일을 일관성있게 지정하기 위해서는 class의 사용이 필수적이다.

```markdown
<!-- class의 사용 -->
.custom {
  background: red
}

<div class="custom">클래스!</div>

<!-- id의 사용 -->
#custom {
  background: yellow
}

<div id="custom">아이디!</div>
```

# 4.css에서 class의 하위 태그대한 속성을 지정하는 방법.
```markdown
선택자1 선택자2 { 속성1: 값; 속성2: 값 }
```
위와 같이 태그이름 사이에 공백을 넣는 선택자는 부모 태그 하위에 있는 태그에 스타일을 적용시킨다.

```markdown
.example a {
  color: red
}

<div class="example">
  &lt;a href="http://naver.com&gt;네이버로 이동&lt;/a&gt;
</div>
```

# 5. 다중 조건 선택자

여러 조건을 동시에 만족하는 태그에 스타일을 적용할 수 있다(AND 연산)
```markdown
태그이름#아이디 { 속성: 속성값; }
태그이름.클래스명 { 속성: 속성값; }
.클래스명#아이디 { 속성: 속성값; }

exam)
<!-- div 태그를 사용하며, example 클래스를 사용하는 요소 -->
div.example { background: red; }
<div class="example">우와!</div>

<!-- 두개 이상의 클래스를 만족 -->
.example1.example2 { color: red }
<span class="example1 example2">우와!</span>

```

쉼표(,)를 통해 두선택자 중 하나라도 만족시 적용할 수 있다(OR 연산)
```markdown
#아이디, .클래스명 { 속성: 속성값; }
태그이름, .클래스명 { 속성: 속성값; }

div, .example { color: red; }
<div> asdfasdf </div>

&lt;span class="example&gt;우와!</span>
```

  


  
</div></body>]]></content><author><name>Your Name</name></author><category term="web" /><summary type="html"><![CDATA[1. header, body, footer 역할 및 선언방법]]></summary></entry><entry><title type="html">코틀린의 컴파일 과정</title><link href="https://sonsation.github.io/kotilin/compile-process/" rel="alternate" type="text/html" title="코틀린의 컴파일 과정" /><published>2019-08-23T04:34:28+00:00</published><updated>2019-08-23T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/compile-process</id><content type="html" xml:base="https://sonsation.github.io/kotilin/compile-process/"><![CDATA[<h1 id="코틀린의-컴파일-과정">코틀린의 컴파일 과정</h1>

<p>컴파일 과정을 알기 이해하기 위해서는 코틀린은 정적 타입(Statically typed) 지정 언어라는 것을 알아야한다. 정적 타입 지정이라는 말은 프로그램의 모든 구성 요소의 타입이 컴파일 되는 시점에 알 수 있고, 컴파일러가 타입을 검증해준다는 뜻이다.</p>

<h3 id="정적-타입-지정의-장점">정적 타입 지정의 장점</h3>
<ol>
  <li>실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 없어서 메소드 호출이 빠르다.</li>
  <li>컴파일러가 정확성을 검증하기 때문에 오류가 생길 화률이 줄어든다.</li>
  <li>코드에서 다루는 객체가 어떤 타입인자 알 수 있어서 코드를 볼 때 편하다.</li>
</ol>

<p>코틀린의 경우도 자바와 같이</p>

<p>코드를 컴퓨터가 읽을 수 있도록 컴파일러가 class 파일 형식의 바이트 코드로 바꿔준다.
코틀린은 정적 타입지정 언어이기 때문에 컴파일러가 추론할 수 있는 변수들을 추론하여 스마트 캐스트해주고 추론 할 수 없는 타입들에 대해서 오류를 발생하여 개발자에게 보고한다. 또한 tailrec, inline 키워드같은 키워드를 쓰는 함수들에 대해 코드를 복사하거나 변환하여 컴파일한다.</p>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[코틀린의 컴파일 과정]]></summary></entry><entry><title type="html">코틀린 스트림함수</title><link href="https://sonsation.github.io/kotilin/stream/" rel="alternate" type="text/html" title="코틀린 스트림함수" /><published>2019-08-23T04:34:28+00:00</published><updated>2019-08-23T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/stream</id><content type="html" xml:base="https://sonsation.github.io/kotilin/stream/"><![CDATA[<h1 id="스트림함수">스트림함수</h1>

<p>자바8에서는 리스트나 맵과 같은 컬렉션에 포함된 자료들을 손쉽게 다룰 수 있도록 스트림(stream)기능을 제공한다.
코틀린 표준 라이브러리에서 제공하는 함수들은 자방 8의 스트림 기능을 사용하진 않지만, 통상적으로 ‘스트림함수’라고 부른다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># map()함수에서는 컬렉션 내 인자를 다른 값 혹은 타임으로 변환할 때 사용한다.</span>
val cities = listOf("Seoul", "Newyork", "London")
cities.map { city -&gt; city.toUpperCase() }.forEach { println(it) }
//출력결과
SEOUL
NEWYORK
LONDON

<span class="gh"># mapIndexed()함수를 사용하면 컬렉션 내 포함된 인자의 인덱스 값을 변환 함수 내에서 사용할 수 있다</span>
val numers = 1..10
numbers.mapIndexed { index, number -&gt; index <span class="err">*</span> number }.forEach { print(it) }
//출력 결과
0 1 4 9 16 25 ...

<span class="gh"># mapNotNull()은 컬렉션 내 각 인자를 변환함과 동시에, 변환한 결과가 널 값인 경우 이를 무시한다.</span>
val cities = listonf {"Seoul", "Newyork", "London"}
cities.mapNotNull { city -&gt; if(city.lengt == 5) city else null }.forEach { println(it) }
//출력 결과
Seoul

<span class="gh"># flatMap() 함수는 map()함수와 유사하게 컬렉션 내 인자를 다른 형태로 변환해주는 역할을 한다. 하지만 map() 함수와 달리 변환 함수의 반환형이 interable이다.</span>
val number = 1..5
numbers.flatMap { number -&gt; 1..number }.forEach { print(it) }
//출력 결과
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5

<span class="gh"># groupBy()함수는 컬렉션 내 인자들을 지정한 기준에 따라 분류하며, 각 인자들의 리스트를 포함하는 맵 형태로 결과를 반환한다.</span>
val cities = listonf {"Seoul", "Newyork", "London"}
cities.groupBy { city -&gt; if(city.length == 5) "A" else "B" }.forEach { key, value -&gt; println("$key, $value") }
//출력 결과
A, Seoul
B, Nework
B, London

<span class="gh"># filter()함수는 컬렉션 내 인자들 중 주어진 조건과 일치하는 인자만 걸러주는 역할을 한다.</span>
val cities = listonf {"Seoul", "Newyork", "London"}
cities.filter { city -&gt; city.length &lt;= 5 }.forEach { println(it) }
//출력 결과
Seoul

<span class="gh"># take() 함수의 인자로 받은 개수만큼만을 인자로 갖는 리스트를 반환</span>
cities.take(1).forEach { println(it) }
//출력결과
Seoul

<span class="gh"># takeLast() take()함수와 반대</span>
cities.takeLast(1).forEach { println(it) }
//출력결과
London

<span class="gh"># takeWhile() 첫 번째 인바부터 시작하여 주어진 조건을 만족하는 인자까지를 포함하는 리스트를 반환한다.</span>
cities.takeWhile { city -&gt; city &lt;= 5 }.forEach { println(it) }
// 출력 결과
Seoul

<span class="gh"># takeLastWhile() takeWhile()함수와 반대</span>
cities.takeLastWhile { city -&gt; city &gt;= 5}.forEach { println(it) }
// 출력 결과
없음

<span class="gh"># drop()함수는 take()함수와 반대의 역할을 하며, 조건을 만족하는 하목을 컬렉션에서 제외한 결과를 반환한다.</span>
<span class="gh"># drop(), dropLast(), dropWhile(), dropLastWhile() 존재</span>
cities.drop(1).forEach { println(it) }
//출력결과
Newyork
London

<span class="gh"># first() 함수는 컬렉션 내 첫번째 인자를 반환한다. 조건을 사용하여 조건을 만족하는 첫번쨰 인자를 반환하는 것도 가능</span>
<span class="gh"># 조건을 만족하는 인자가 없는 경우 NoSuchElementException 예외를 발생, firstorNull() 함수를 사용하면 예외 대신 널 값을 반환 한다.</span>
println(cities.first())
println(cities.last())
println(cities.first { city -&gt; city.lenth == 5 })
println(cities.firstOrNull { city -&gt; city.isEmpty() })
//출력결과
Seoul
London
Seoul
null

<span class="gh"># distinct() 함수는 컬렉션 내에 포함된 항목 중 중복된 항목을 거러낸 결과를 반환한다.</span>
<span class="gh"># distinctBy() 함수를 사용하면 비교에 사용할 조건을 직접 설정 할 수 있다.</span>
cities.distinct().forEach { println(it) }
//출력결과
Seoul
Newyork
London

cities.distinctBy { city -&gt; city.contains("e") }.forEach { println(it) }
//출력결과
Seoul
London

<span class="gh"># zip() 함수는 두 컬렉션 내의 자료들을 조합하여 새로운 자료를 만들떄 사용된다.</span>
<span class="gh"># 두 컬렉션 간 자료의 개수가 달라도 사용하 수 있으며, 이 경우에 반환되는 컬렉션의 자료수는 조합에 사용하는 컬렉션의 수 중 더 적은 쪽을 따라간다.</span>
<span class="gh"># 기본값으로 조합된 결과를 Pair로 만들어주며, 원하는 경우 조합 규칙을 사용자가 정의할 수 있다.</span>

<span class="gh"># JoinToString() 함수는 컬렉 션 내 자료를 문자열 형태로 변한함과 동시에, 이를 조합하여 하나의 문자열로 생성한다.</span>
println(cities.joinToString())
println(cities.joinToString(" "))
println(cities.joinToString("|"))
//출력결과
Seoul, Newyork, London
Seoul Newyork London
Seoul|Newyotk|London

<span class="gh"># count() 함수는 컬렉션 내 포함된 자료의 개수를 반환하며, 조건식을 추가하며 해당 조건을 만족하는 자료의 개수를 출력한다.</span>
println(cities.count())
println(cities.count { city -&gt; city.length == 5 }
//출력결과
3
1

<span class="gh"># reduce() 함수는 컬렉션 내 자료들을 모두 합쳐 하나의 값으로 만들어주는 역할을 한다.</span>
<span class="gh"># reduce() 함수는 컬렉션 내 첫번쨰 자료부터 조합을 시작하며, reduceRight() 함수는 컬렉션 내 마지막 자료부터 시작한다</span>
</code></pre></div></div>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[스트림함수]]></summary></entry><entry><title type="html">코틀린의 특징(고차함수, 익명함수, 인라인함수, 클로저, 꼬리회귀, 제네릭)</title><link href="https://sonsation.github.io/kotilin/features/" rel="alternate" type="text/html" title="코틀린의 특징(고차함수, 익명함수, 인라인함수, 클로저, 꼬리회귀, 제네릭)" /><published>2019-08-21T04:34:28+00:00</published><updated>2019-08-21T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/features</id><content type="html" xml:base="https://sonsation.github.io/kotilin/features/"><![CDATA[<h2 id="일급함수">일급함수</h2>

<p>일급함수는 스스로 객체로써 취급되는 함수로 다른 함수를 파라미터로 전달받고 반환할 수 있는 함수를 뜻한다.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린의 경우</span>
fun print(body: (Int, Int) -&gt; Int) {
 println(body(5, 5))
}

print({a, b -&gt; a})

<span class="gh"># 자바의 경우</span>
public final void print(@NotNull Fuction body) {
 Object result = body.invoke(5, 5);
 System.out.println(result);
}

</code></pre></div></div>

<p>코틀린의 경우 위와 같이 자동으로 컨버팅 될 수 있기 때문에 유동적인 방법도 사용가능하다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>private fun print(body: (Int, Int) -&gt; Int) {
 println(body(10, 5))
}

fun sum(a: Int, b: Int) = a + b
fun sub(a: Int, b: Int) = a - b

printResult(::sum) //result = 15
printResult(::sub) //result = 5
</code></pre></div></div>

<h2 id="inline과-noinline">inline과 noinline</h2>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린의 경우</span>
fun doSomething(body: () -&gt; Unit) {
 body()
}

fun callFunction() {
 doSomeThing{ println("out") }
}
 
 # 자바의 경우
public void doSomethings(Function body) {
 body.invoke();
}
 
public void callFunction() {
 doSomething(new Function() {
  @Override
  public void invoke() {
   System.out.println("out");
  }
 });
}
</code></pre></div></div>
<p>코틀린이나 자바에서 inline 키워드를 쓰지 않는 경우 조합하는 함수가 많아질수록 계속 N개 만큼의 function object가 생성되어 메모리 할당과 가상 호출에 의한 런타임 오버헤드가 발생한다. 이럴 때 사용하게 되는 것이 inline 키워드이다. inline 함수로 정의된 함수는 컴파일 단계에서 호출하는 방식이 아니라 코드 자체가 복사되는 방식이다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>inline fun doSomeThing(body: () -&gt; unit) {
 body()
}

fun callFunction() {
 doSomething { println("out") }
</code></pre></div></div>

<p>inline 함수를 사용하면 Function 인스턴스를 만들지 않고 callFunction 내부에 삽입되어 바로 선언된다. inline 함수는 private 키워드를 사용하여 정의할 수 없고 internal을 사용해야한다. 모든 람다함수에 inline을 쓰고싶지 않을 경우 noinline 키워드를 추가한다.</p>

<p>-인라인 함수의 장,단점
 인라인 함수를 쓰면 메모리 할당과 오버헤드에 효과적이고 메서드를 호출하는게 아니라 복사하기 때문에 성능의 향상으로 이어지지만 컴파일시 변환되는 Byte Code의 길이는 더 길어진다.</p>

<h2 id="꼬리재귀">꼬리재귀</h2>
<p>talerec은 꼬리재귀(tail recursive)라는 의미로, 추가적인 연산이 없이 자신 스스로 재귀적으로 호출하다가 어떤 값을 리턴하는 함수를 의미한다.</p>

<p>자신만 반복적으로 호출하는 재귀함수는 while과 같이 루프를 사용하는 코드로 변환이 가능하다. 이렇게 변환하면 재귀함수가 홏ㄹ되면서 소비되는 스택을 아낄 수 있다.
루프는 동일한 결과를 출력하면서 재귀함수보다 더 적은 자원을 사용하게 된다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="gh"># 재귀함수</span>
fun factorial(n: Int, acc: Int): Int {
 return if (n &lt;= 0) {
  acc
 } else {
  factorial(n-1, n<span class="err">*</span>acc)
 }
}

<span class="gh"># 꼬리재귀</span>
fun factorial(n: Int, acc: Int): Int {
 return if (n &lt;= 0) {
  acc
 } else {
  factorial(n-1, n<span class="err">*</span>acc)
 }
}

</code></pre></div></div>

<p>두 방식의 결과는 같지만 바이트 코드를 비교하면 과정은 다르게 수행되었다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 재귀함수가 컴파일된 바이트 코드를 자바로 변환시</span>
public static final int factorial(int n, int acc) {
 if (n &lt;= 0) {
  return acc;
 }
 return factorial(n-1, n<span class="err">*</span>acc)
}

<span class="gh"># 꼬리재귀가 컴파일된 바이트 코드를 자바로 변환시</span>
public static fianl int factorial(int n, int acc) {
 for (int n2 = n; n2 &gt; 0; n2--) {
  acc = acc <span class="err">*</span> n2;
 }
 return acc;
}
</code></pre></div></div>
<p>위의 코드와 같이 꼬리재귀를 사용하면 루프코드로 컴파일된다.</p>

<h2 id="제네릭">제네릭</h2>
<p>코틀린에서 사용하는 제네릭은 자바에서 사용하는 것과 동일하게 사용할 수 있지만, 자바에서 사용하는 제네릭은 정의를 하지 않아도 기본 Object로 만들어주지만, 코틀린에서 사용하는 제네릭은 명시적으로 꼭 적어주도록 만들었다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># Java Generics 정의</span>
interfacce Generic<span class="nt">&lt;T&gt;</span> {
 void setItem(T item);
}

<span class="gh"># Kotilin Generics 정의</span>
interface Generic<span class="nt">&lt;in</span> <span class="na">T</span><span class="nt">&gt;</span> {
 fun setItem(item: T)
}
</code></pre></div></div>
<p>자바와 코틀린의 인터페이스 정의는 동일하면 T타입을 제네릭으로 선언하였다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린에서 제네릭을 상속 받는 경우</span>
class Sample : Generic<span class="nt">&lt;Generic</span> <span class="na">Type을</span> <span class="na">정의</span><span class="nt">&gt;</span> {
 overrie fun setItem(item: generic Type을 정의) {
  //doSomeThing
 }
}
</code></pre></div></div>

<h2 id="고차함수">고차함수</h2>
<p>고차 함수는 함수를 파라미터로 가져오고 함수를 리턴할 수 있다. 주요 유스케이스는 콜백이며, 자바에서 인터페이스를 생성하고 한쪽에서 인터페이스를 구현해야 하는 반면에 코틀른에서는 함수를 변수에 저장할 수 있어 나중에 사용할 수 있다. 또는 또 다른 함수 안에서 생성될 수 있다. 함수가 선언되지 않았는데 전달되는 것을 람다 또는 익명 함수라고 한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 변수로 함수 넘기기</span>
fun calc(x: Int, y:Int, operation: (Int, Int)-&gt;Int) = operation(x, y)
run { println(calc(5,5, {x, x -&gt; x+x})) }
//실행결과 : 10

<span class="gh"># 함수 리턴</span>
fun getCalcFunctions(action: Int): (Int, Int)-&gt;Int {
  when(action)
    1 -&gt; return {x: Int, y:Int -&gt; x+y}
    2 -&gt; return {x: Int, y:Int -&gt; x-y}
}

val calFunction = getCalcFunctions(2)
run { println(calFunction(5, 5)) }
//실행결과 : 0
</code></pre></div></div>

<h2 id="익명함수">익명함수</h2>
<p>익명함수라는 말은 람다식을 지칭한다. 익명 함수라는 말은 쉽게 말해서 “fun” 키워드를 통해 생성한 함수가 아닌것을 의미한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 기본형태</span>
val lambda09 = { parm1: Int, parm2: Int -&gt; parm1 + parm2 }

fun main(args: Array<span class="nt">&lt;String&gt;</span>) {
 println(lambda09(1, 2))
}
</code></pre></div></div>
<p>함수를 “fun”키워드를 통해 생성하지 않고 변수에 할당하는 모습을 볼 수 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 내용이 여러 줄일 경우 가장 마지막 줄이 반환값이 된다.</span>
val lambda09 = {parm1: Int, parm2: Int -&gt;
 println("labmda")
 parm1 + parm2
}

<span class="gh"># 인자가 없으면 매개변수 부분을 입력하지 않아도 된다.</span>
val labmda09 = {
 val parm1 = 10
 val parm2 = 10
 println("${parm1 + parm2}")
}
</code></pre></div></div>

<h2 id="클로저">클로저</h2>

<p>클로저(Closure)는 상위 함수의 영역(outer scope)의 변수를 접근할 수 있는 함수를 말한다. 코틀린은 클로저를 지원하며, 그렇게 때문에 익명함수는 함수 밖에서 정의된 변수에 접근할 수 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fun add(x: Int): (Int) -&gt; Int {
 return fun(y: Int): Int {
  return x + y
 }
}
 
fun main(args: Array<span class="nt">&lt;String&gt;</span>) {
 val func = add(10)
 val result = func(20)

</code></pre></div></div>
<p>위의 코드에서 add 함수는 익명함수를 리턴한다. 익명함수는 전역변수도, 익명함수의 인자도 아닌 외부에서 정의된 변수 x에 접근하지 못해 컴파일 에러가 발생할 것 같지만 코틀린이 클로저를 지원하기 때문에 컴파일 에러가 발생하지 않는다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># forEach 함수는 익명함수를 인자로 받는다. 람다식으로 생성한 익명함수도 클로저 함수이며, outer scope의 변수에 접근할 수 있다.</span>
var sum = 0
ints.filter { it &gt; 0 }.forEach {
 sum = sum + it
}
print(sum)

<span class="gh"># 자바로 아래처럼 리스너를 만들면 컴파일 에러 발생</span>
int x = 5;

view.setOnClickListener(new View.OnClickListener() {
 @Override public void onClick(View v) {
  System.out.prinln(x); //x가 final이 아니기 때문에 클로저를 지원하지 않는 자바에서는 컴파일 에러가 발생.
 }
});

<span class="gh"># 코틀린은 가능!</span>
 var x = 5
 
 view.setOnClickListener {
  println(x)
 }
</code></pre></div></div>

<p>코틀린 레퍼런스 클로저 설명에 의하면 람다식 또는 익명함수(로컬 함수 및 객체 식)는 해당 클로저에 액세스 할 수 있다. 클로저에서 캡처된 변수는 람다에서 수정할 수 있다라고만 되어 있다. obejct-C나 스위프트의 클로저의 개념과는 해석이 다른 것 같다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var sum = 0
ints.filter { it &gt; 0 }.forEach {
 sum += it
}
println(sum)
</code></pre></div></div>

<p>함수형 프로그래밍의 클로저라는 기능에 대해 알아보기 위해 스위프트의 클로저 개념을 공부해보기로 했다.
스위프트에서 클로저란 한 번만 사용하기 위한 일회용 함수를 작성할 수 있는 블럭이라고 한다. 자신이 정의되웠던 문맥으로부터 모든 상수와 변수의 값을 캡쳐하거나 레퍼런스를 저장한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 클로저의 형태</span>
{ (param1: Int, param2: Int: Stirng) -&gt; Int in
 return param1 + param2
}

<span class="gh"># 클로저 예제</span>
let numbers = [1, 4, 56, 22, 5]
func sortAscending(_ i: Int, - j: Int) -&gt; Bool {
 return i &lt; j
}

//클로저 미사용
let sortedNumbers = numbers.sorted(by: sortAscending)

//클로저 사용
let sortedNumbers = numbers.sorted(by: { (i: Int, j: Int) -&gt; Bool in
  return i &lt; j
})
</code></pre></div></div>
<p>클로저가 단일 명령문만을 가지고 있다면 ‘return’키워드 없이도 명령문의 값을 반환할 수 있다.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>let sortedNumbers = numbers.sorted(by: { (i: Int, j: Int) -&gt; Bool in
 i &lt; j
 })
</code></pre></div></div>

<p>스위프트는 클로저의 타입을 문맥으로부터 추론해 결정한다. 클로저에서 ‘타입’, ‘반환 타입’, ‘return’을 제거해서 축약할 수 있다.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// 매개변수 타입 추론 축약
let sorted = numbers.sorted(by: { i, j in i &lt; j})

// 축약형 인수형 문법
let sortedNubmers = numbers.sorted(by: { $0 &lt; $1 })
</code></pre></div></div>

<p>축약형 인수형 문법 구조 적용 매개변수 이름을 사용하지 않고 인자로 넘어오는 순서대로 $0, $1,…를 사용하면 in과 매개변수 목록도 없앨 수 있다.
두 인자를 받아서 연산자에 넘기는 경우 ‘&lt;’연산자를 바로 넘겨도 된다.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>let sortedNumbers = numbers.sorted() { $0 &lt; $1 }

<span class="gh"># 클로저가 함수에 대한 유일한 인자일 때 괄호를 완전히 생략할 수 있다.</span>
let sortedNumbers = numbers.sorted { $0 &lt; $1 }
</code></pre></div></div>

<p>스위프트의 클로저를 공부하면서 느낀점은 코틀린의 클로저와 다르다는 것이다. 스위프트에 대한 견해 많이 부족하여 스위프트의 클로저의 내용과 코틀린 클로저의 내용을 제대로 비교할 수는 없지만 나름대로 생각한 차이점을 스위프트 축약 단계를 예로 들어 써보고자 한다.</p>

<h3 id="1-클로저가-단일-명령문만을-가지고-있는경우-return키워드를-생략할-수-있다">1. 클로저가 단일 명령문만을 가지고 있는경우 ‘return’키워드를 생략할 수 있다.</h3>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린의 경우 단일 명령문이 아니더라도 마지막 명령문이 자동으로 리턴된다.</span>
val add = {x: Int, y: Int -&gt;
 x <span class="err">*</span> y
 x + y
}

println(add(10, 20))
//결과값: 30
</code></pre></div></div>
<h3 id="2-매개변수-타입-추론-축약">2. 매개변수 타입 추론 축약</h3>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린의 경우에도 매개변수 타입을 추론할 수 있다면 축약가능하다.</span>
fun exam(x: Int, operation: (Int, Int) -&gt; Int) {
    
}

exam(10, {x, y -&gt; x + y})
</code></pre></div></div>
<h3 id="3-코틀린의-경우-인수형으로-축약할-수-없다">3. 코틀린의 경우 인수형으로 축약할 수 없다.</h3>

<h3 id="4-클로저가-함수에-대한-유일한-인자일-때-괄호-생략">4. 클로저가 함수에 대한 유일한 인자일 때 괄호 생략</h3>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 코틀린의 경우에도 함수가 유일한 인자일 때 괄호를 생략할 수 있다.</span>
fun exam(operation: (Int, Int) -&gt; Int) {
    
}

exam {x, y -&gt; x + y}

<span class="gh"># 마지막 인자가 함수일 때 소괄호 밖 중괄호로 인자를 뺄 수 있다.</span>
fun exam(x: Int, operation: (Int, Int) -&gt; Int) {
    
}

exam(10) {x, y -&gt; x + y}
</code></pre></div></div>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[일급함수]]></summary></entry><entry><title type="html">코틀린의 smart cast</title><link href="https://sonsation.github.io/kotilin/smart-cast/" rel="alternate" type="text/html" title="코틀린의 smart cast" /><published>2019-08-21T04:34:28+00:00</published><updated>2019-08-21T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/smart-cast</id><content type="html" xml:base="https://sonsation.github.io/kotilin/smart-cast/"><![CDATA[<p>스마트캐스팅</p>

<p>자바에서 instanceOf 연산자를 사용하여 객체의 자료형을 확인하더라도 이를 변환하기 위해서는 확인했던 자료형으로 다운 캐스팅을 해줘야한다.
코틀린에서 이러한 불편함을 해소하고 간결함을 얻기 위해 is로 추론이 가능한 경우 캐스팅 없이 해당하는 자료형으로 객체가 변환되도록 컴파일러가 스마트 캐스팅을 지원한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># null인지 확인</span>
fun main() {
  val name: String? = "sonsation"
  if (name != null) println(name.length) // name의 null체크를 한후 널이 아니면 String 타입으로 스마트 캐스팅 된다. (null 체크 후 name을 강제 호출 하지 않아도 된다)
}
</code></pre></div></div>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 자바의 스마트 캐스팅 미지원</span>
Object string = "is String!";

if (string instanceOf String) {
  String text = (String)string; // 별도의 다운 캐스팅을 해줘야함.
  System.out.println(text);
}

<span class="gh">#코틀린의 스마트 캐스팅 지원</span>
val string = "is String!"

if (string is String)
  println(string) // 별도의 캐스팅 없이 타입 체크만으로 캐스팅 되었기 때문에 따로 캐스팅이 필요없다.
</code></pre></div></div>

<p>이뿐만 아니라 코틀린의 스마트 캐스팅은 람다식에서도 적용된다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 스마트 캐스팅 미적용</span>
val sum: (Int, Int)-&gt;Int = {x: Int, y:Int -&gt; x + y}

<span class="gh"># 스마트 캐스팅 적용</span>
val sum = {x: Int, y:Int -&gt; x + y}
</code></pre></div></div>

<p>-제약조건
 var은 언제든지 값이 변할 수 있는 변수이기 때문에 스마트 캐스트가 지원되지 않는다.</p>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[스마트캐스팅]]></summary></entry><entry><title type="html">코틀린 엘비스 &amp;amp; 장점 및 사이드 이펙트</title><link href="https://sonsation.github.io/kotilin/elvis-feature/" rel="alternate" type="text/html" title="코틀린 엘비스 &amp;amp; 장점 및 사이드 이펙트" /><published>2019-08-21T04:34:28+00:00</published><updated>2019-08-21T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/elvis-feature</id><content type="html" xml:base="https://sonsation.github.io/kotilin/elvis-feature/"><![CDATA[<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code></code></pre></div></div>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">코틀린 제네릭</title><link href="https://sonsation.github.io/kotilin/generic/" rel="alternate" type="text/html" title="코틀린 제네릭" /><published>2019-08-21T04:34:28+00:00</published><updated>2019-08-21T04:34:28+00:00</updated><id>https://sonsation.github.io/kotilin/generic</id><content type="html" xml:base="https://sonsation.github.io/kotilin/generic/"><![CDATA[<p>코틀린도 자바와 같이 Genric을 지원한다.
일반적으로 자바와 다르지 않으나, 코틀린은 좀더 많은 기능을 지원한다.
자바는 제네릭 개념이 들어가면ㅁ서 하위 호환성을 위해 타입을 정의하지 않고도 사용할 수 있으나, 코틀린은 반드시 타입을 정의하고 써야한다.</p>

<h2 id="extension-property">Extension Property</h2>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fun main() {
  val letters = ('a'..'z').toList()
  println(letters.slice<span class="nt">&lt;Char&gt;</span>(0..2))
  println(letters.slice(10..13))
}
</code></pre></div></div>

<p>extension property만 제네릭 하게 만들 수 있다. 일반 property에 제네릭을 사용하면 컴파일 오류가 난다.</p>

<h2 id="제네릭-클래스">제네릭 클래스</h2>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># JAVA</span>
public class Car<span class="nt">&lt;T&gt;</span> {
  private T data;
  
  public void set(T data) {
    this.data = data
  }
  
  public T get() {
    return data;
  }
}

<span class="gh">#Kotlin</span>
class Car<span class="nt">&lt;T&gt;</span> {
  private var data:T? = null
    get() = { return data }
    set(value) = { field = value }
</code></pre></div></div>

<p>자바와 같은 방법으로 &lt;&gt;형태로 선언하면 된다.</p>

<h2 id="type-parameter-limitation">Type parameter limitation</h2>
<p>자바에는 extends나 super를 사용하여 사용한 타입을 제한할 수 있다.
코틀린에서는 :를 사용하여 상한 typ (upper bound)를 설정 할 수 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># JAVA</span>
<span class="nt">&lt;T</span> <span class="na">extends</span> <span class="na">Number</span><span class="nt">&gt;</span> T sum(List<span class="nt">&lt;T&gt;</span> list)

<span class="gh"># Kotilin</span>
fun <span class="nt">&lt;T:</span> <span class="na">Number</span><span class="nt">&gt;</span> List<span class="nt">&lt;T&gt;</span>.sum(): T
</code></pre></div></div>

<p>코틀린에서 타입 상한을 설정하면 상한 타입으로 취급할 수 있다.</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fun <span class="nt">&lt;T:</span> <span class="na">Comparable</span><span class="err">&lt;</span><span class="na">T</span><span class="nt">&gt;</span>&gt; max(first: T, second: T): T {
  return if (first &gt; second) first else second
}

fun main() {
  println(max("kotlin", "java"))
}
</code></pre></div></div>

<p>위 예제에서는 T는 Comparable<T> 상한을 갖는다. 즉 max()를 사용할때의 인자는 Comparable을 구현하고 있어야 한다는 의미가 된다.</T></p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
fun <span class="nt">&lt;T&gt;</span> ensureTrailingPeriod(seq: T)
  where T: CharSequence, T: Appendable {
  
  if (!seq.endWith('.')) {
    seq.append('.')
  }
}

fun main() {
  val helloWorld = StirngBuilder("Hello World")
  ensureTrailingPeriod(helloWorld)
  println(helloWorld)
}
</code></pre></div></div>

<p>두개의 제약을 하는 경우 where 연산자를 씁니다. 이때의 함수 타입은 나열된 타입들은 전부 만족해야 한다.</p>

<h2 id="non-null-type-parameter">Non-Null Type parameter</h2>
<p>코틀린에서 타입의 기본은 Non null이다.
다만 제네릭인 경우에만 기본값이 nullable이다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Friend&lt;T&gt; {
  fun getUniqueIt(value: T) {
    value?.hashCode()
  }
}

fun main() {
  val friend = Friend()
  friend.getUniqueId(null)
}
</code></pre></div></div>

<p>따라서 NonNull인 타입으로 제한하려면 명시적으로 &lt;T: Any&gt;로 선언해야 한다.</p>
<T>만 선언한다면 &lt;T: Any?&gt;와 같다.
  
## Generic의 runtime 동작

자바에서는 실행시점에 instance의 타입인자를 확인할 수 없다. 이는 JVM이 type erase를 하기 때문이다.
다만 코틀린에서는 inline을 통해서 이를 피할 수 있다.

클래스가 생성되어 instance가 되면 더 이상 인자 정보를 가지고 있지 않는다. 예를 들어 List<String>을 객체로 만들었다면, 이는 List 타입만 알 뿐 내부에 저장된 원소type의 정보는 알 수 없다.



 
</String></T>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[코틀린도 자바와 같이 Genric을 지원한다. 일반적으로 자바와 다르지 않으나, 코틀린은 좀더 많은 기능을 지원한다. 자바는 제네릭 개념이 들어가면ㅁ서 하위 호환성을 위해 타입을 정의하지 않고도 사용할 수 있으나, 코틀린은 반드시 타입을 정의하고 써야한다.]]></summary></entry><entry><title type="html">코틀린의 장점</title><link href="https://sonsation.github.io/kotilin/pros/" rel="alternate" type="text/html" title="코틀린의 장점" /><published>2019-08-20T12:26:28+00:00</published><updated>2019-08-20T12:26:28+00:00</updated><id>https://sonsation.github.io/kotilin/pros</id><content type="html" xml:base="https://sonsation.github.io/kotilin/pros/"><![CDATA[<h2 id="1null-safety">1.Null safety</h2>

<p>코틀린은 ‘non-nullable’을 기본으로 해 null 참조를 제거한다. 컴파일러가 초기화되지 않는 사용을 막는다. null 값을 가지고 싶으면 그 타입을 ‘nullable’로 선언해야 한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># nullable 선언</span>
var nullable: String? = null

<span class="gh"># nullable</span>
//null check 후 실행
if (nullable != null) nullable.doSomething()

//Safe call
nullable?.doSomething()

<span class="gh"># nullable 강제호출</span>
//null 인지 non-null 인지 구분하지 않고 강제로 호출 null이면 NullPointException을 발생한다.
nullable!!.doSomething()
</code></pre></div></div>
<h2 id="2확장함수">2.확장함수</h2>

<p>클래스에 상속하거나 데코레이더 패턴을 사용하지 않고도 추가할 수 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fun String.doSomethig(): String {

}
</code></pre></div></div>

<p>클래스 이름(String)을 수신 객체 타입(receiver type)이라 부르며, 수신 객체는 확장 함수에 접근할 떄 사용하게 되는 객체다.
확장 함수는 내부에서만 사용할 수 있는 private, protected 멤버에 접근할 수 없어서 캡슐화를 깰 수 없다.</p>

<h2 id="3data-class">3.Data class</h2>
<p>대부분의 앱은 데이터 기반이라 스스로 데이터를 가지고 있기 위해 속성과 필드만 있는 클래스를 만든다. 자바에서 이 과정은 각 필드의 get/set 메서드를 요구하기 때문에 매우 귀찮고 번거롭다 코틀린은 클래스를 싱글라인으로 모든 속성과 함께 선언할 수 있다. 컴파일러가 모든 getter/setter를 만들고 toString(), copy() 메서드를 생성한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data class User(var name:String, var age: Int)
</code></pre></div></div>

<h2 id="4immutability">4.immutability</h2>

<p>멀티스레드를 구현할 때 변수가 mutable하면 어떤 스레드에서 접근할 때 변화가능하고, 이것을 막기위해 동기화를 구현한다. 동기화는 복잡성과 실행시간을 증가시킴. 데이터가 변할 일이 없으면 멀티 스레드에서 에러없이 접근이 가능하다. 코틀린에서 변수는 var/val로 선언한다. var은 재설정 가능한 변수이고 val은 한번 설정되면 변할 수 없다. 자바에서는 비슷한 기능으로 final 키워드를 가지지만 var/val은 더 큰 의미를 가지는데 속성을 선언할 때 var은 getter/stter로 정의하는 반면, val은 getter와 private setter로 정의하고 항상 생성자에서 변수가 할당되어야 한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var animals = listOf("lion", "tiger")
animals.add("zebra") //컴파일 에러
</code></pre></div></div>

<h2 id="5범위-지정-함수-apply-with-let-also-run">5.범위 지정 함수 (apply, with, let, also, run)</h2>

<p>5개의 함수는 전달받는 인자와 작동방식, 결과가 매우 비슷하기 때문에 많은 경우에 서로를 대체해서 사용할 수 있다.
이런 특성 때문에 상황에 따라 어떤 함수를 사용하는 것이 적절한 사용법인지 고민해 볼 필요가 있다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># JAVA 텍스트 뷰에 대한 설정을 하기 위해 textView를 명시해줘야 한다.</span>
TextView textView = findViewById(R.id.textView);
textView.setText("text")
textView.setSize(16)

<span class="gh"># 범위 지정 함수의 수신객체가 매개변수로 암시적으로 전달된다.</span>

<span class="gh"># 코틀린 let은 지정된 값이 null이 아닌 경우에 코드를 실행할 수 있기 때문에 safe call을 할 수 있다.</span>
textView?.let {
  it.text = "text"
  it.size = 16
}

<span class="gh"># also also는 apply와 마찬가지로 수신 객체를 반환하지만 객체의 사이드 이팩트를 확인하거나, 수신객체의 프로퍼티에 데이터를 할당하기 전에 해당 데이터의 유효성을 검사할 때 사용.</span>

class book(author: Person) {
  val author = author.also {
    requireNotNull(it.age)
    print(it.name)
  }
}

<span class="gh"># apply 람다 내부에서 수신 객체의 함수를 사용하지 않고 수신 객체 자신을 다시 반환하려는 경우 사용.</span>
val person = Person().apply {
  name = "sonsation"
  age = 27
}

<span class="gh"># run 어떤 값을 계산할 필요가 있거나 여러개의 지역 변수의 범위를 제한할 때 사용.</span>
val inserted: Boolean = run {
    val person: Person = getPerson()
    val personDao: PersonDao = getPersonDao()
    personDao.insert(person)
}
fun printAge(person: Person) = person.run {
    print(age)
}

<span class="gh"># with Non-nullable 수신 객체 이고 결과가 필요하지 않은 경우에만 사용.</span>
val person: Persion = getPerson()
  with(person) {
    print(name)
    print(age)
  }
}
</code></pre></div></div>

<p>범위 지정 함수는 코드 가독성을 향상시키기 좋다. 하지만, 원칙적으로 중첩은 하지 않는게 좋다. 이 함수들은 수신 객체를 this또는 생략하며, 수신객체의 이름을 다르게 지정할 수 없기 때문에 중첩될 경우 혼동하기 쉬워진다.</p>

<h2 id="6higher-order-functions-and-lambdas">6.Higher-order functions and lambdas</h2>
<p>고차 함수는 함수를 파라미터로 가져오고 함수를 리턴할 수 있다. 주요 유스케이스는 콜백이며, 자바에서 인터페이스를 생성하고 한쪽에서 인터페이스를 구현해야 하는 반면에 코틀른에서는 함수를 변수에 저장할 수 있어 나중에 사용할 수 있다. 또는 또 다른 함수 안에서 생성될 수 있다. 함수가 선언되지 않았는데 전달되는 것을 람다 또는 익명 함수라고 한다.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh"># 변수로 함수 넘기기</span>
fun calc(x: Int, y:Int, operation: (Int, Int)-&gt;Int) = operation(x, y)
run { println(calc(5,5, {x, x -&gt; x+x})) }
//실행결과 : 10

<span class="gh"># 함수 리턴</span>
fun getCalcFunctions(action: Int): (Int, Int)-&gt;Int {
  when(action)
    1 -&gt; return {x: Int, y:Int -&gt; x+y}
    2 -&gt; return {x: Int, y:Int -&gt; x-y}
}

val calFunction = getCalcFunctions(2)
run { println(calFunction(5, 5)) }
//실행결과 : 0

<span class="gh"># 코드의 간결성을 위해 규칙이 존재</span>
<span class="gh"># 1. 함수의 맨 마지막 인자가 람다라면() 안에서 뺴내서 밖에 람다를 표현할 수 있다.</span>
<span class="gh"># 2. 인자가 하나라면 그 인자는 람다식 내부에서 'it'으로 받을 수 있다.</span>
<span class="gh"># 3. 인자가 하나이면서 그 인자가 람다타입 이라면 ()을 생략할 수 있다.</span>

people.maxBy ({p: Person -&gt; p.age})
people.maxBy () {p: Person -&gt; p.age}
people.maxBy {p: Person -&gt; p.age}
people.maxBy {it.age}

</code></pre></div></div>]]></content><author><name>Your Name</name></author><category term="kotilin" /><summary type="html"><![CDATA[1.Null safety]]></summary></entry></feed>