티스토리 두번째 글
아자아자
맥북은 참 뭐랄까...한/영키를 굳이 capslock에 놔야했던걸까? 이거땜에 자꾸 한영전환이 안돼서 스트레스받아서 설정하느라 혼이 났다.
그치만 설정 다 했으니까 nobody 아무도 날 막을수없으셈~ 전환 잘되는군 good~
참... 애증이다 애증
코드테스트 사이트:play.kotlinlang.org
참조강좌:유튜브 디모의 코틀린
고차함수와 람다함수
//고차함수:함수를 마치 클래스에서 만들어낸 '인스턴스처럼' 취급하는 법
//=>함수를 '패러미터'로 넘겨줄 수도 있고 '결과값으로 반환'받을 수도 있다.
//코틀린에선 모든 함수를 고차함수로 사용 가능하다.
//패러미터가 뭐지? 요소? 입력받는 요소?
fun main() {
b(::a)//함수 b를 호출하되 함수a를 패러미터로 넘겨줌
//:: : 일반 함수를 고차 함수로 변경해주는 연산자, 콜론 두개!
}
fun a (str: String){ //a라는 함수 만들어 문자열을 패러미터로 받는다
//문자열을 받고, 반환형은 없는 함수!
println("$str 함수 a")//패러미터로 받은 문자열 포함한 출력
}
fun b (function: (String)->Unit){ //함수를 나타낸 자료형의 일종,기억!
//함수 받을 패러미터 이름은 function
//함수 만들면서,함수 a를 고차함수 형식의 패러미터로 받을수 있도록 함
//함수를 패러미터로 받을 때 함수의 자료형은 어떻게 해야할까?
//(자료형,자료형,...)(함수의패러미터들->자료형(반환형)
//이런 형태의 함수를 모두 패러미터로 받을 수 있게 됨!
//Unit은 값이 없다는 형식!
function("b가 호출한")//받아온 함수 실행하되 문자열도 같이 넘겨줌
}
//정리)main함수가 a함수를 b함수에 패러미터로 넘겼고
//b함수는 받아온 a함수에 "b가 호출한"이라는 값을 넘겨서 호출함
//최종적으로 a라는 함수가 실행되면서 "b가 호출한 함수 a"라고 출력됨
그.런.데
패러미터로 넘길 함수를 굳이 이름까지 붙여 따로 만들 필요가 있을까요?
함수를 람다식으로 표현하는 "람다함수"가 등장!
//람다함수는 일반함수와 달리 '그 자체가 고차함수'라서 별도의 연산자없이
//변수에 담을 수 있다!
fun main() {
b(::a) //일반함수를 고차함수로 만들어주는 연산자 ::
val c: (String)->Unit = {str->println("$str 람다함수")}
//val a:Int 처럼 일반적인 변수에 자료형 쓰듯, 함수의 형식((string)-unit) 써줌
//원래는 str:String 처럼 콜론,자료형 써줘야함, 근데 이미 받아오는
// 함수의 자료형이 기술되어있으므로(String) 생략가능!
//패러미터로 받아온 문자열을 매칭해 줄 변수 이름 써줌(str)
// *str은 string으로 받아온 값을 람다함수 내에서 사용할 변수이름임
//동작시킬 구문 :str->println() 함수 형식처럼 화살표 써주고
// 패러미터로 받은 함수를 포함하여 뭔가를 출력
b(c) //함수 b에 람다함수 c를 넘겨 실행!
}//이때, 람다함수 축약 가능
// val c:{str:String->println("$str 람다함수")}
// 람다식 안에만 패러미터의 자료형 기술!
// 이에 맞게 알아서 (String)->Unit 자료형으로 저장됨!
fun a(str: String) {
println("$str 함수 a")
}
fun b (function: (String)->Unit) {
function("b가 호출한")
}
//흐음...솔직히 마지막?축약은 이해잘안됨
함수를 변수로 사용할 수 있게 되었다~~
//람다함수 보충설명
//1. 람다함수도 여러줄로 사용할 수 있다.
val c:(String)->Unit={str->
println("$str 람다함수")
println("여러 구문을")
println("사용가능합니다")
}
val calculate:(Int, Int)->Int={a,b->
println(a)
println(b)
a+b //람다함수가 여러줄이 되는 경우 마지막값이 반환됨
}
//보충설명 2.람다함수에 패러미터가 없다면?실행할 구문들만 나열하면 된다!
val a:()->Unit={println("패러미터가 없어요")}
//보충설명 3.패러미터가 하나뿐이라면 it 사용
//(패러미터 여러개면 람다함수 내에서 패러미터 이름 일일이 써줬었음)
val c:(String)->Unit={println("$it 람다함수")}
//패러미터가 String 하나라서 패러미터 이름 안써주고 바로 println 쓰고
//그 안에서는 it이라고 패러미터 지칭함
스코프함수
//스코프함수:함수형 언어의 특징을 좀더 편리하게 사용할수있도록 기본제공하는 함수들
//클래스에서 생성한 인스턴스를 scope함수에 전달하면
// 인스턴스의 속성이나 함수를 좀 더 깔끔하게 불러 쓸 수 있다!
//scope 함수:apply, run, with, also, let 5가지
//apply:인스턴스를 생성한 후 변수에 담기 전에 초기화 과정 수행할 때 많이 쓰임
//run:apply처럼 run스코프 안에서 참조연산자를 사용하지 않아도됨(공통)
// 일반 람다함수처럼 인스턴스 대신 마지막 구문에 결과값을 반환함
fun main() {
//책 변수
var a = Book("디모의 코틀린", 10000).apply{
name = "[초특가]"+name
discount()
}
//기존에는 인스턴스를 저장한 변수(a)를 통해 참조연산자를 사용하여
//a.name a.discount()과 같이 속성과 함수를 사용했지만
//apply를 이용하면 인스턴스를 생성하자마자
//그 인스턴스에 참조연산자를 사용하여 apply를 붙이고 중괄호로 람다함수????를
//하나 만들어 apply의 scope '안'에서 직접 인스턴스의 속성과 함수를
//참조연산자 없이!! 사용이 가능하다~
//또한 apply는 인스턴스 자신을 다시 반환!하므로
//이렇게 생성되자마자 조작된 인스턴스를 변수에 바로 넣어줄 수 있다!
//apply와 같은 스코프 함수를 사용하면 main함수와 '별도의 scope'에서
//인스턴스의 변수와 함수를 조작하므로 코드가 깔끔해진다~
var b = a.run(){
println(a.price)
a.name
}
//run은 스코프 안에서 참조연산자 사용안하는건 apply와 같지만
//일반 람다함수처럼, 인스턴스 대신 마지막 구문에 결과값을 반환한다는 차이점!
//*이렇게 쓰면 가격은 출력하지만 마지막 구문인 이름은 반환하여
// b라는 변수에 할당됨
//따라서 이미 인스턴스가 만들어진 후에 인스턴스의 함수나 속성을
//scope내에서 사용해야 할 때 유용함
------->회색부분은 var a 부분 대체해서 사용
//이제 apply를 사용해 만들어진 변수a의 내용을 run을 이용해 출력해봅시다~
a.run{
println("상품명:${name}, 가격:${price}원")
}
//변수 a에 참조연산자를 사용하여 run을 붙이고 중괄호 안에서 인스턴스의
//속성 이름을 직접 사용하여 내용을 출력해준다
//실행해보면 apply에서 수정한 책 이름과 할인된 가격인 8000원이 잘 출력됨.
}
class Book(var name:String, var price:Int){
//book이라는 클래스 만들어 이름과 가격을 파라미터로 받음
fun discount()//가격을 낮춰주는 함수 생성
{
price -= 2000
}
}
with
//<with>
//run과 기능은 동일
//but 단지 인스턴스를 참조연산자 대신 패러미터로 받는다
//a.run{...}
//with(a){...} -->형태만 좀 다르다!
//
//<also/let>
//also:처리가 끝나면 '인스턴스'를 반환(apply와 같은기능)
//let:처리가 끝나면 '최종값'을 반환(run과 같은 기능)
//차이점:apply,run은 참조연산자 없이 인스턴스의 변수와 함수 사용 가능
// also, let은 마치 패러미터로 인스턴스를 넘긴것처럼 'it'을 통해
// 인스턴스를 사용할 수 있다
// Q)왜 굳이 얘네만 패러미터로 인스턴스 사용?
// A)같은 이름의 변수나 함수가 'scope 바깥에 중복'되어있는 경우에
// 혼란을 방지하기 위해~
fun main(){
var price = 5000 //book클래스의 속성 중 하나와 이름이 중복됨
//main함수의 변수가 인스턴스 내의 속성보다 우선돼서 5000이 출력됨
var a = Book("디모의 코틀린",10000).apply {
name = "[초특가]" + name
discount()
}//변수a는 book클래스에 "디모의 코틀린"과 10000이라는 속성을 넣은
//인스턴스이고, apply를 이용해서 바로 함수와 속성을 사용할 수 있도록 함~
//자신을 반환한다
a.run {
println("상품명: ${name},가격:${price}원")
}
a.let{
println("상품명: ${it.name},가격:${it.price}원")
//원래는 그냥 price로 썼는데 main함수 변수랑 겹쳐서
//run->let 대체하고 it키워드도 같이 사용해줌
}//apply도 이처럼 스코프 외부와 겹치는 속성 있으면 'also'로 대체!
}
class Book(var name:String, var price:Int)
{
fun discount()
{
price -=2000
}
}
//정리
//스코프 함수는 인스턴스의 속성이나 함수를 scope내에서 깔끔하게 분리하여
//사용할 수 있다는 점 때문에 코드의 가독성을 향상시킨다는 장점
인스턴스라는 말때문에 의미가 헷갈려서 게슈탈트붕괴가 올 것만 같아~
오마이갓 강의는 6분인데 내용은 6분이 아니야😱
음 프레쉬한 뇌로 수정하러 올게요~ 23.04.04.
음... 지금 수정하는거 진짜 노양심~ 23.04.30.
'코틀린 문법' 카테고리의 다른 글
6. 형변환과 배열, 타입추론과 함수 (0) | 2023.04.30 |
---|---|
5. 변수와 자료형-코틀린 (0) | 2023.04.30 |
4. 익명객체와 옵저버 패턴-코틀린 7일차 (0) | 2023.04.11 |
3. 오브젝트-코틀린 6일차-(2) (0) | 2023.04.04 |
1. 프로젝트 구조, 스코프-코틀린 5일차 (0) | 2023.04.04 |