Scala 스터디 2

young·2021년 9월 26일
0

클래스

  • 스칼라는 따로 생성자가 존재하지 않아, 클래스 바디 부분의 코드가 바로 실행
  • 일반 클래스와 추상 클래스 모두 상속 가능 (extends), 추상 클래스 선언 (abstract)
  • 추상 클래스는 매개변수를 가질 수 있고, 기본 메소드를 선언만 하거나 구현할 수 있음
scala> abstract class Person(name:String, age:Int) {	// 추상 클래스 
	|	def work
	|	def status(str:String)
   	|	def greeting() = println(s"${name}님은 ${age}살 입니다.")
   	| }
scala> class Player(name:String, age:Int) extends Person(name, age) {	// 상속 
	|	def work = { println("일합니다.")}
	|	def status(str:String) = println(s"${str} 상태 입니다.")
	| }
scala> var p = new Player("Cal", 10) 
scala> p.work
일합니다.
scala> p.status("깨있는") 
깨있는 상태 입니다.
  • 클래스나 트레잇을 봉인 가능 (sealed)
  • 봉인된 클래스와 하위 타입이 모두 한 파일에 있어야 하므로 관리 효율성이 높아짐
//file.scala
scala> sealed abstract class Furniture	// 봉인 추상 클래스
scala> case class Couch() extends Furniture
scala> case class Chair() extends Furniture

//file2.scala
scala> case class Desk() extends Furniture
illegal inheritance from sealed class Furniture	// 봉인 클래스를 이용하려면 한 파일 내에 같이 있어야 함

클래스 멤버변수

  • 멤버 변수를 선언 시 가변/불변 변수를 명시적으로 선언 가능, 생략도 가능
기본 멤버 변수가변 변수 var불변 변수 val
메소드 생성 Xgetter, setter 메소드 생성 읽기, 쓰기getter 메소드 생성
클래스 내부에서만 사용 가능읽기, 쓰기읽기
scala> class Person(name:String, age:Int)	// 클래스 선언 
scala> val p = new Person("David", 30)	// 클래스 생성 
scala> class A	// 멤버 변수 생략

scala> class Animal(name:String) { println(s"${name}") }	// 기본 멤버 변수
scala> class Dog(var name:String) { println(s"${name}") }	// 가변 변수
scala> class Cat(val name:String) { println(s"${name}") }	// 불변 변수
scala> var ani = new Animal("동물")
scala> var dog = new Dog("개")
scala> var cat = new Cat("고양이") println(ani.name)	// 기본 멤버 변수 접근 불가
error...
scala> println(dog.name)
개
scala> println(cat.name)
고양이
scala> dog.name = "바둑이"
dog.name: String = 바둑이
scala> cat.name = "나비"	// 불변 변수 재할당 불가
error...

//멤버 변수는 종류 상관 없이 기본값 설정 가능
scala> class Person1(name:String, age:Int)
scala> class Person2(var name:String, var age:Int=10)
scala> class Person3(val name:String="Ted", val age:Int) 
scala> var p1 = new Person1("David", 30)
scala> var p2 = new Person2("Tomphson")
scala> var p3 = new Person3("David", 12)
//name에 기본값을 입력할 수 없어서 error 
scala> var p3 = new Person3(12)
error...

클래스 메소드

  • 메소드 오버라이드 가능 (override)
  • 클래스 생성 시 new를 이용해 메소드 재정의 가능
scala> class Person(name:String, age:Int, val job:String) {
	|	def greeting() = println(s"${name}님은 ${age}살 입니다.") 
	|	def work() = println(s"직업은 ${job}입니다.")
	| }
scala> class Writer(name:String, age:Int) extends Person(name, age, "") { 
	|	override def work() = println(s"직업은 작가입니다.")	// overrding
	| }
scala> var w = new Writer("David", 15)
scala> w.greeting 
David님은 15살 입니다.
scala> w.work
직업은 작가입니다.

scala> var p = new Person("David", 15, "학생") { 
	|	override def work() = println(s"job is ${job}.")
	| }
scala> p.greeting 
David님은 15살 입니다.
scala> p.work 
job is 학생.

케이스 클래스

  • case를 이용해 선언, 인스턴스 생성할 때 new 사용하지 않아 초기화가 간단함
  • 케이스 클래스는 불변 데이터로 멤버변수는 기본적으로 불변 변수로 선언됨
  • 멤버 변수의 데이터를 이용해 데이터 비교
  • toString, hashCode, equals, copy() 자동으로 생성
scala> case class Person(name:String, age:Int) 
scala> var p = Person("A", 10)
scala> p.toString 	// toString
res0: String = Person(A, 10)
scala> p.hashCode 	// hashCode 
res1: Int = 649684425
scala> var p1 = Person("B", 20) 
scala> p.equal(p1) 	// equal 
res2: Boolean = false
scala> p1 = p.copy() 	// copy() 
p1: Persion = Person("A", 10)

패턴 매칭

  • 파라미터 값과 case문의 값을 비교한 값의 결과 반환
// 기본 문법 
param match {
	case value1 => "value1"	// param 값과 value1 값을 비교해 일치하는 값의 결과 반환
	case _ => "default value"	// 언더바_는 어떤 값도 일치하지 않을 때 결과 반환 
}

scala> def matching(x:Int): String = x match {	// 파라미터 x와 case문의 값들을 비교해 일치하는 값 반환
	| 	case 0 => "zero"
	| 	case 1 => "one"
	| 	case _ => "many"
	| }
scala> matching(1) 
res0: String = one 
scala> matching('A') 
res1: String = many
  • 케이스 클래스의 멤버 변수 값을 이용한 패턴 매칭 (일반 클래스는 패턴 매칭에 사용 불가)
  • if <논리 표현>문을 이용해 패턴 처리를 구체화하는 방법인 패턴 가드 이용 가능
scala> abstract class Notification
scala> case class Email(sender:String, title:String, body:String) extends Notification 
scala> case class SMS(caller:String, message:String) extends Notification
scala> case class VoiceRecording(contactName:String, link:String) extends Notification 
scala> def showNotification(nofitication:Notification): String = {
	| 	notification match {
	| 		case Email(email, title, _) => s"You got an email from $email with title: $title"	// body는 반환값에 사용하지 않아 _로 처리 가능
	| 		case SMS(number, message) => s"You got an SMS from $number! Message: $message"
	| 		case VoiceRecording(name, link) => s"You received a Voice Recording from $name! Click the link to hear it: $link"
	|	}
	| }
scala> def showImportantNotification(nofitication:Notification, importantPeopleInfo:Seq[String]): String = {
	| 	notification match {
	| 		case Email(email, _, _) if importantPeopleInfo.contains(email) => s"You got an email from special someone!"
	| 		case SMS(number, _) if importantPeopleInfo.contains(number) => s"You got an SMS from special someone!"
	| 		case other => showNotification(other) 
	|	}
	| }

scala> val importantPeopleInfo = Seq("123-4567", "jenny@gmail.com")
scala> val someSms = SMS("123-4567", "Are you there?")
scala> val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
scala> val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
scala> val importantSms = SMS("123-4567", "I'm here! Where are you")
  • 케이스 클래스 타입을 자동으로 확인한 패턴 매칭
scala> abstract class Device
scala> case class Phone(model: String) extends Device {
	|	def screenOff = "Turning screen off"
	| }
scala> case class Computer(model: String) extends Device { 
	|	def screenSaverOn = "Turning screen saver on..."
	| }
// Device를 받아서 클래스 타입을 자동으로 확인
scala> def goIdle(device: Device) = device match { 
	|	case p: Phone => p.screenOff
	|	case c: Computer => c.screenSaverOn
	| }

scala> val phone = Phone("Galaxy")
scala> val computer = Computer("Macbook") 
scala> println(goIdle(phone))
Turning screen off
scala> println(goIdle(computer)) 
Turning screen saver on...
  • 숫자, 문자열 형식의 값을 이용한 패턴 매칭
scala> object PatternMatchingSample extends App {
	| 	val VALID_GRADES = Set("A", "B", "C", "D", "F")
	| 	def letterGrade(value: Any): String = value match {
	| 		case x if (90 to 100).contains(x) => "A"
	|		case x if (80 to 90).contains(x) => "B"
	|		case x if (70 to 80).contains(x) => "C"
	|		case x if (60 to 70).contains(x) => "D"
	|		case x if (0 to 60).contains(x) => "F"
	|		case x: String if VALID_GRADES(x.toUpperCase()) => x.toUpperCase()
	|	}
	| 	println(letterGrade(91))
	|	println(letterGrade(72))
	|	println(letterGrade(44))
	|	println(letterGrade("B"))
	| }

믹스인 컴포지션

  • 클래스와 트레잇을 상속할 때 서로 다른 부모의 변수, 메소드를 섞어서 새로운 정의 만드는 것
scala> abstract class A { val message: String }
scala> class B extends A { val message: "I'm an instance of class B" }	// 추상 클래스 A를 상속하면서 변수 초기화
scala> trait C extends A { def loudMessage = message.toUpperCase() }	// 추상 클래스 A를 상속하면서 함수 선언
scala> class D extends B with C	// 믹스인하여 클래스 B의 message를 이용하는 loudMessage 함수 생성할 수 있음

scala> val d = new D
scala> println(d.message)
I'm an instance of class B 
scala> println(d.loudMessage) 
I'M AN INSTANCE OF CLASS B

Trait

  • 자바의 인터페이스와 유사
  • 메소드를 정의만 해놓을 수도 기본 구현을 할 수도 있지만, 생성자 파라미터는 가질 수 없음
  • 가변/불변 변수 모두 선언 가능
  • 트레잇을 구현하는 클래스에서 가변 변수는 수정 가능하지만 불변 변수는 수정 불가능
  • 트레잇의 기본 메소드는 상속되고, override로 메소드 재정의
  • extends로 상속하고 여러 개의 트레잇을 with로 동시 구현 가능
  • 멤버변수를 가질 수는 없지만 여러 개의 트레잇 상속 가능
scala> trait Machine {
	|	val serialNumber: Int = 1 
	|	def work(messgae: String)
	| }
scala> trait krMachine {
	|	var countryCode: String = "kr" 
	|	def print() = println("한글 출력")
	| }
scala> class Computer(location: String) extends Machine with krMachine { 
	|	this.countryCode = "us"	// 값 변경
	|	def work(messgae: String) = println(message)
	| }
scala> class Car(location: String) extends Machine with krMachine { 
	|	def work(messgae: String) = println(message)
	|	override def print() = println("운전 중입니다.")	// 메소드 재정의
	| }

scala> var machine = new Computer("노트북") 
scala> var car = new Car("포르쉐") 
scala> machine.work("computing...")
computing...
scala> machine.print() 
한글 출력
scala> println(machine.countryCode) 
us
scala> car.print()
운전 중입니다.
scala> println(car.countryCode) 
kr

0개의 댓글