1. OBJECT

  • 스칼라의 모든 것이 object!
  • 숫자도 object, 문자도 object

Web playgrounds


In [1]:
1+1


Out[1]:
res0: Int = 2

In [2]:
1.0/2


Out[2]:
res1: Double = 0.5

In [3]:
"a"+"b"


Out[3]:
res2: String = "ab"

In [4]:
"a"+("b")


Out[4]:
res3: String = "ab"

In [ ]:
1 + 1
:type 1
1.0 / 2
:type 1.0
"a" + "b"
:t "a"
"ab" * 3
"a".+("b")
"ab".*(3)
"ab" + 'c'
'ab' + "c"
BigInt("12345679") * 9


val a = 1
var b = 2
b = 3
a = 4
val c = 1 + 2; c + 3


def size = 2
5 * size
def square(x: Int) = x * x
square(2)
square(square(2))
def sumOfSquare(x: Int, y: Int) = square(x) + square(y)
def abs(x: Int) = if (x >=0) x else -x

In [2]:
"ab"+3


Out[2]:
res1: String = "ab3"

In [3]:
"a".*(3)


Out[3]:
res2: String = "aaa"

In [4]:
"a"*3


Out[4]:
res3: String = "aaa"

In [5]:
"ab" + 'c'


Out[5]:
res4: String = "abc"

In [6]:
'a' + "bc"


Out[6]:
res5: String = "abc"

In [6]:
val a = 1
a = 2


cmd6.sc:2: reassignment to val
val res6_1 = a = 2
               ^
Compilation Failed

In [7]:
var b = 2
b = 3


Out[7]:
b: Int = 3

Scala의 특징

  • 간결한 표현
  • 강력한 타입체크
  • 준수한 성능
  • 방대한 라이브러리 : 자바 라이브러리 사용 가능

Spark

  • Spark native
  • Compile-time type checked

scala> 1+1

  • 1+1 : expresion
  • \<Int>, 2 : type, 결과

Object와 상호작용하기


In [7]:
"hello".toUpperCase
// argument가 없는 경우


Out[7]:
res6: String = "HELLO"

In [8]:
// argument가 있는 경우
// sequence하면 모두 take가 가능
"heelo".take(3)


Out[8]:
res7: String = "hee"

In [9]:
"hello".take(2)


Out[9]:
res8: String = "he"

In [10]:
// Infix operator
1+1


Out[10]:
res9: Int = 2

In [11]:
// 위와 같은 표현
1.+(1)


Out[11]:
res10: Int = 2

In [12]:
"hello" take 2


Out[12]:
res11: String = "he"

Literal Objects

Numbers


In [13]:
1
// 32 bit


Out[13]:
res12: Int = 1

In [14]:
1.0
// 64 bit


Out[14]:
res13: Double = 1.0

In [15]:
1.0f


Out[15]:
res14: Float = 1.0F

In [16]:
1L


Out[16]:
res15: Long = 1L

불리언


In [18]:
true


Out[18]:
res17: Boolean = true

In [19]:
false


Out[19]:
res18: Boolean = false

char


In [20]:
'a'


Out[20]:
res19: Char = 'a'

string


In [21]:
"hello world"


Out[21]:
res20: String = "hello world"

In [26]:
"""hello
|
|!!!"""


Out[26]:
res25: String = """
hello
|
|!!!
"""

In [27]:
""" "hi" """


Out[27]:
res26: String = """
 "hi" 
"""

null


In [23]:
null
// 스칼라에선 null을 안쓰는 방식으로 코딩하는 것을 추천


Out[23]:
res22: Null = null

UNIT

  • return하는 것이 없는 것

In [24]:
()

In [41]:
println("hello world")


hello world

In [29]:
:type println("hello-world")

// Unit이라고 떠야하는데 왜 오류지 : repl에선 됨


SyntaxError: found "type \n\n// Unit\uc774\ub77c\uace0 \ub5a0\uc57c", expected BacktickId | PlainId at index 23
ntln("hello-world").type 
                    ^

object 정의하기

빈 jobect


In [ ]:


In [28]:
object Test


Out[28]:
defined object Test

In [29]:
Test


Out[29]:
res28: Test.type = $sess.cmd27Wrapper$Helper$Test$@5277ee75

In [30]:
object Test {}


Out[30]:
defined object Test

In [31]:
Test


Out[31]:
res30: Test.type = $sess.cmd29Wrapper$Helper$Test$@278bc9af

method가 있는 object


In [36]:
object Test2 {
    def name: String="홍길동"
    def name1: String="바보"
}


Out[36]:
defined object Test2

In [35]:
Test2.name


Out[35]:
res34: String = "홍길동"

In [37]:
Test2.name1


Out[37]:
res36: String = "바보"

repl에서 여러줄을 사용하려면 :paste라고 쓰고 해야함!

파라미터 받는 method


In [1]:
object Test3 {
    def hello(to: String): String="Hello " + to
}

In [2]:
Test3.hello("Alice")


Out[2]:
Hello Alice

In [40]:
Test3 hello "hi"


Out[40]:
res39: String = "Hello hi"

Default parameter Values


In [43]:
object Test4 {
    def hello(firstName: String, lastName: String="!"): String=
    "Hello " + firstName + " " +lastName
    
}
// lastName이 없으면 "!"


Out[43]:
defined object Test4

In [44]:
Test4.hello("tony")


Out[44]:
res43: String = "Hello tony !"

In [45]:
Test4.hello("tony", "stark")


Out[45]:
res44: String = "Hello tony stark"

keyword parameters


In [46]:
Test4.hello(lastName="hi", firstName="kkkk")


Out[46]:
res45: String = "Hello kkkk hi"

Apply Method

  • 이름을 말 안하고 바로할 수 있음
  • 예약된 것을 수행
  • 자주 쓰고, 많이 쓰는 것을 이렇게 만듬
  • 함수처럼 작동해서 object를 사용해 함수를 만듬
  • 실제 스칼라 function도 이렇게 되어 있음

In [51]:
object inc {
    def apply(n: Int): Int = n+1
}
// 인자는 항상 타입을 적어줘야 함
// return 타입을 항상 작성해주는 것을 권장


Out[51]:
defined object inc

In [48]:
inc.apply(1)


Out[48]:
res47: Int = 2

In [49]:
inc(1)


Out[49]:
res48: Int = 2

In [54]:
def add(n: Int): Int ={
    println("adding!")
    n+1
}
// 마지막꺼만 타입 리턴


Out[54]:
defined function add

In [55]:
add(10)


adding!
Out[55]:
res54: Int = 11

In [60]:
def add(n: Int): Int ={println(s"adding $n"); n+1}
// s를 써야 %n에 타입을 넘길 수 있음


Out[60]:
defined function add

In [61]:
add(10)


adding 10
Out[61]:
res60: Int = 11

Fields


In [62]:
object Test5 {
    val name: String = "Alice"
    def hello(other: String): String = name + " says hi to " + other
}


Out[62]:
defined object Test5

In [63]:
Test5.name


Out[63]:
res62: String = "Alice"

In [64]:
Test5.hello("Bob")


Out[64]:
res63: String = "Alice says hi to Bob"

Methods vs Fields

  • 큰 차이는 없고, 이름이 겹치면 안됨

In [67]:
object Test6 {
    val simpleField = {
        println("evaluating simpleField")
        42
    }
    lazy val lazyField = {
        println("Evaluating lazy")
        42
    }
    def noParameterMethod = {
        println("evaluating")
        42
    }
}
// 생성 당시엔 아무것도 실행이 안되고
// object가 호출되면 필드값들이 실행


Out[67]:
defined object Test6

In [66]:
Test6


evaluating simpleField
Out[66]:
res65: Test6.type = $sess.cmd64Wrapper$Helper$Test6$@5325517a

In [66]:
// val은 처음 실행될 떄 한번
// lazy가 실행될 때 시작
// def는 계속
// 사이드 이펙트

In [68]:
Test6.lazyField


evaluating simpleField
Evaluating lazy
Out[68]:
res67: Int = 42

In [69]:
Test6.simpleField


Out[69]:
res68: Int = 42

In [70]:
Test6.simpleField
// println이 안됨! 처음만 실행


Out[70]:
res69: Int = 42

In [71]:
Test6.noParameterMethod


evaluating
Out[71]:
res70: Int = 42

In [72]:
Test6.noParameterMethod


evaluating
Out[72]:
res71: Int = 42

In [72]:
// lazy는 드물게 호출되는 케이스에 사용

In [73]:
object foo {
  def a = {
    println("a")
    1
  }
  val b = {
    println("b")
    a + 2
  }
  def c = {
    println("c")
    a
    b + "c"
  }
}


Out[73]:
defined object foo

In [74]:
foo.c + foo.b + foo.a


b
a
c
a
a
Out[74]:
res73: String = "3c31"

In [74]:
// foo가 불리는 순간 b, a+2니까 a가 찍히고 c가 찍히고 a가 찍히고 b는 value라 안나오고

Hello World


In [76]:
// vi HelloWorld.scala file
object HelloWorld {
  def main(args: Array[String]): Unit = {
    println("Hello, world!")
  }
}
// main method를 실행!
// 리턴이 없는 Unit


Out[76]:
defined object HelloWorld

In [ ]:
> scala HelloWorld

In [76]:
> scalac HelloWorld.scala
// scalac는 컴파일 -> .class라는 파일 생성되며 $가 붙은 것은 추후 설명해드림

더 간단하게!!


In [77]:
object HelloWorld extends App {
  println("Hello, world!")
}


Out[77]:
defined object HelloWorld

In [77]:
// extends App이라고 달아주면 main 함수 안을 바로 작성할 수 있음

BLOCKS

  • 중괄호로 감싸면 한 덩어리처럼 실행

In [79]:
{1; 2; 3}


Out[79]:
res78_0: Int = 1
res78_1: Int = 2
res78_2: Int = 3
  • repl에선 오류가 나는데, console:12: warning: a pure expression does nothing in statement position; multiline expressions might require enclosing parentheses
  • 1,2는 하는게 없다
  • 사이드 이펙트시 사용

In [80]:
{
  println("This is a side-effect")
  println("This is a side-effect as well")
  3
}


This is a side-effect
This is a side-effect as well
Out[80]:
res79_2: Int = 3

계산중간값에 이름 붙이기


In [81]:
def name: String = {
  val title = "Doctor"
  val name = "Strange"
  title + " " + name
}


Out[81]:
defined function name

In [82]:
name


Out[82]:
res81: String = "Doctor Strange"

조건


In [83]:
if (1 < 2) "Yes" else "No"
// res: String = Yes


Out[83]:
res82: String = "Yes"

In [ ]:
:type if (1 < 2) "Yes" else "No"
// String

In [84]:
if(1 < 2) println("Yes") else println("No")
// Yes


Yes

In [ ]:
:type if(1 < 2) println("Yes") else println("No")
// Unit

Writing Methods

  • 메소드 입출력 타입 파악 및 메소드 타입 선언부 작성
    • def add(n: Int): Int = ??? 이런식으로 해도 됨
  • 테스트 케이스 준비
  • 코드 실행
  • 메소드 구현
  • 코드 재실행

숙제

  • Double 하나를 입력받아 그 제곱을 출력하는 square method를 가진 calc object를 작성해보세요.

  • Double 하나를 입력받아 그 세제곱을 출력하는 cubic method를 calc object 안에 작성해보세요. 구현할 때 square를 이용해보세요.

  • 위의 두 method를 Double 뿐만 아니라 Int 값도 입력받을 수 있도록 해 보세요


In [98]:
object calc {
    def square(x: Double): Double = x*x
    def square(x: Int): Int = x*x
    def cubic(x: Double): Double = square(x)*x
    def cubic(x: Int): Int = square(x)*x
}

// 함수 이름이 같아도 타입이 다르면 다른거가 됨!! 충격적임ㅋㅋㅋㅋㅋㅋㅋㅋㅋ


Out[98]:
defined object calc

In [95]:
calc.square(2)


Out[95]:
res94: Int = 4

In [97]:
calc.cubic(3)


Out[97]:
res96: Int = 27

In [92]:
calc.cubic(2.0)


Out[92]:
res91: Double = 8.0

In [90]:
println(calc.square(2.0) == 4.0)


true

Scala는 어디에 사용하나요?

  • scala.js ( 노드처럼 프론트와 백엔드를 같이 사용 가능 )
  • 웹서버 ( play framework )
  • Spark