서비스도메인이 youtube.com 이라면,
com.youtube.dimo
com.youtube.dimo.base
com.youtube.dimo.kotlin
com.youtube.dimo.android
com.youtube.dimo.talk
이런 식으로 패키지 이름을 짓는다.
패키지로 어떤 코드 파일을 묶으려면, 상단에 다음과 같이 적어준다.package com.youtube.dimo
package com.youtube.dimo.base // 사용할 외부 패키지
fun main() {
println("Hello!")
}
사용할 외부 패키지가 있는 경우 위와 같이 그 패키지 이름을 적어주고, 만약 두 패키지에서 겹치는 클래스, 변수, 상수 등이 있는 경우 해당 클래스, 변수, 상수를 사용할 때 패키지 이름까지 적어주면서 사용해야 제대로 쓸 수 있다.변수나 함수, 클래스 같은 '멤버'들을 서로 공유하여 사용할 수 있는 범위를 지정해 둔 단위
패키지 스코프
함수 스코프
클래스 스코프
등이 있다.
val a = "패키지 스코프"
class B {
fun print() {
println(a)
}
}
fun main() {
println(a) // 패키지 스코프
B().print() // 패키지 스코프
}
변수 a가 class B나 function main에 속해있지는 않지만 동일한 스코프 내에 있기 때문에 사용할 수 있다.val a = "패키지 스코프"
class B {
val a = "클래스 스코프"
fun print() {
println(a)
}
}
fun main() {
val a = "함수 스코프"
println(a) // 함수 스코프
B().print() // 클래스 스코프
}
스코프 외부에서 스코프 내부에 접근할 때 그 권한을 개발자가 제어할 수 있는 기능
위 접근제한자들은 변수, 함수, 클래스 선언시 맨 앞에 붙여서 사용한다.
위 접근자를 패키지 스코프에서 사용할 때
클래스 스코프에서 사용할 때
접근제한자는 스코프 외부에서 건드리지 말아야 할 기능이나 값들을 안전하게 제한한다.
함수를 마치 클래스에서 만들어낸 인스턴스처럼 취급하는 방법
함수를 parameter로 넘겨줄 수도 있고, 결과값으로 반환받을 수도 있다.
코틀린에서는 모든 함수를 고차함수로 사용 가능하다.
fun main() {
b(::a) //함수를 고차함수 형태로 넘기려면 함수 이름 앞에 콜론을 두 개 붙여주면 된다.
// b함수는 받아온 a 함수에 "b가 호출한"이라는 값을 넣어서 호출하였다.
// print 결과: b가 호출한 함수 a
}
fun a (str: String) {
println("$str 함수 a")
}
fun b (function: (String) -> Unit){ // 함수를 받을 parameter 이름은 function, 자료형은 a의 함수의 형식을 넘겨받아야 함
function("b가 호출한")
}
// 함수의 형식은 사용하려는 함수의 인수와 반환형을 이용하여 (자료형, 자료형, ...) -> (자료형) 으로 나타낸다.
// Unit은 값이 없다는 뜻
패러미터로 넘길 함수에 굳이 이름을 붙여 따로 만들 필요가 없다면, 람다함수를 사용하자.
람다함수는 그 자체가 고차함수이다.
fun main() {
b(::a)
val c: (String) -> Unit = { str -> println("$str 람다함수") }
// str:String -> ...이 기본 형식이지만 함수의 인수부분에 이미 자료형이 들어있어 생략한다.
val c = {str:String -> println("$str 람다함수")} // 이렇게 쓸 수도 있다.
b(c)
}
fun a (str: String) {
println("$str 함수 a")
}
fun b (function: (String) -> Unit){ // 함수를 받을 parameter 이름은 function, 자료형은 a의 함수의 형식을 넘겨받아야 함
function("b가 호출한")
}
타입추론을 이용하여 축약하여 사용한 것이 두 번째 val c 이다. 헷갈린다..
val calculate: (Int, Int) -> Int = {a, b ->
println(a)
println(b)
a+b // 마지막 줄의 값이 반환된다.
}
val a:() -> Unit = {println("패러미터가 없어요")}
val c: (String) -> Unit = {println("$it 람다함수")}
함수형 언어의 특징을 좀 더 편리하게 사용할 수 있도록 기본 제공하는 함수들
클래스의 인스턴스를 scope 함수에 전달하면 인스턴스의 속성이나 함수를 좀 더 깔끔하게 불러 쓸 수 있다.
// 기본 방법
fun main() {
var a = Book("디모의 코틀린", 10000)
a.name = "[초특가]" + a.name
a.discount()
}
class Book(var name: String, var price: Int)
{
fun discount()
{
price -= 2000
}
}
// apply 적용 시
fun main() {
var a = Book("디모의 코틀린", 10000).apply {
// main 함수와 별도의 스코프에서 인스턴스를 조작하게 됨
name = "[초특가]" + name // 참조연산자 없이 적용 가능
discount()
}
}
class Book(var name: String, var price: Int)
{
fun discount()
{
price -= 2000
}
}
fun main() {
var a = Book("디모의 코틀린", 10000).apply {
name = "[초특가]" + name
discount()
}
a.run { // 만들어진 인스턴스에서 사용, 참조연산자 필요 x
println("상품명: ${name}, 가격: ${price}원")
}
}
class Book(var name: String, var price: Int)
{
fun discount()
{
price -= 2000
}
}
a.run {...}
with(a) {...} // 차이는 이것 뿐! 인스턴스를 parameter로 받는다.
fun main() {
var price = 5000
var a = Book("디모의 코틀린", 10000).apply {
name = "[초특가]" + name
discount()
}
a.run {
// main 함수 내의 price 변수가 instance 내의 price 속성보다 우선시된다.
println("상품명: ${name}, 가격: ${price}원") // 5000원이 출력된다.
}
a.let {
println("상품명: ${it.name}, 가격: ${it.price}원") // 8000원이 출력된다.
}
}
class Book(var name: String, var price: Int)
{
fun discount()
{
price -= 2000
}
}
apply와 also, run과 let은 같은 역할이지만 also와 let은 스코프 내의 속성의 이름이 스코프 바깥의 변수 이름과 중복될 수 있을 때 사용한다.
스코프 함수는 인스턴스의 속성이나 함수를 스코프 내에서 깔끔하게 분리하여 사용할 수 있으므로 코드의 가독성을 향상시킨다.
var a = Person("박보영", 1990)
코드 아무 곳에서나 호출하여 호출한 횟수를 카운팅하거나 초기화할 수 있는 counter라는 오브젝트를 만들자.
fun main() {
println(Counter.count) // 0, 객체가 최초 사용시 자동 생성됨
Counter.countUp() // 위에서 생성한 객체를 사용하는 것
Counter.countUp()
println(Counter.count) // 2
Counter.clear()
println(Counter.count) // 0
}
object Counter {
var count = 0
fun countUp() {
count++
}
fun clear() {
count = 0
}
}
이런 식으로, 따로 인스턴스를 만들어주는 과정 없이 사용할 수 있다.
클래스의 인스턴스 기능은 그대로 사용하면서, 인스턴스 간에 공용으로 사용할 속성 및 함수를 별도로 만드는 것이다. 기존의 언어들이 가지고 있는 Static 멤버와 비슷하다.
*static member: 클래스 내부에서 별도의 영역에 고정적으로 존재, 인스턴스를 생성하지 않아도 공용으로 사용 가능한 속성이나 함수
fun main() {
var a = FoodPoll("짜장")
var b = FoodPoll("짬뽕")
a.vote()
a.vote()
b.vote()
b.vote()
b.vote()
println("${a.name}: ${a.count}") // 짜장 2
println("${b.name}: ${b.count}") // 짬뽕 3
println("총계: ${FoodPoll.total}") // 총계 5
}
class FoodPoll(val name: String) {
companion object {
var total = 0
}
var count = 0
fun vote() {
total++
count++
}
}
a와 b가 서로 다른 인스턴스임에도 total을 공유한다.