2023 02 01
2023-02-01¶
Scala 기초 투어¶
추출 오브젝트 => 뭔소리지...?¶
- 개요
unapply메서드가 있는 object
- 예시
object Twice { def apply(x: Int): Int = x * 2 def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None } object TwiceTest extends App { val x = Twice(21) x match { case Twice(n) => Console.println(n) } }object CustomerID { def apply(name: String) = s"$name--${Random.nextLong()}" def unapply(customerID: String): Option[String] = { val stringArray: Array[String] = customerID.split("--") if (stringArray.tail.nonEmpty) Some(stringArray.head) else None } } val customer1ID = CustomerID("Sukyoung") // Sukyoung-23239492918 customer1ID match { case CustomerID(name) => println(name) // prints Sukyoung case _ => println("Couldn't extract") }
For문¶
- 개요
- For문 다루는 방법 제공
- 약간 stream과 느낌이 비슷
-
예시
- for안의 if로 필터링
- yield로 매핑
case class User(name: String, age: Int) val userBase = List( User("Travis", 28), User("Kelly", 33), User("Jenny", 44), User("Dennis", 23) ) // List[String] val twentySomethings = for (user <- userBase if user.age >= 20 && user.age < 30) yield user.name // add this to a list, map function과 비슷 twentySomethings.foreach(println) // Travis, Dennis
- 중첩 포문 + generator 합쳐서 쇼부
- yield로 매핑 안하면 Unit으로 반환
제네릭 클래스¶
- 개요
- Java의 제네릭과 비슷
- 강타입언어에서 필요
A를 주로 표시자로 씀
-
예시
- 자바랑 비슷하지?
- 서브 타입 쌉가능
- invariant (공뭐시꺵이.. 자바에도 있는 개념이지?)
- Stack[A]와 Stack[B]는 A==B 일때만 하위로 사용가능
Variance¶
- 개요
- 서브 타이핑 관계
- 해당 Variance 중 선택 가능: covariant, contravariant, invariant (어노테이션 없음)
- 자바보다 훨씬 유연한 제네릭 Variance를 제공
- Invariance
- 타입 파라미터 기본적으로 스칼라에서 Invariant 함
-
Covariance
- type[+A]로 정의가 된다면...
- type[부모] <- type[자식] 이 성립이 됨
- 다만 출력에 대해서만 적용
- 대표적으로 List가 Covariance
def printAnimalNames(animals: List[Animal]): Unit = animals.foreach { animal => println(animal.name) } val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom")) val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex")) // prints: Whiskers, Tom printAnimalNames(cats) // prints: Fido, Rex printAnimalNames(dogs)
- type[+A]로 정의가 된다면...
- Contravariance
- 이번엔 출력이 아니라 집어 넣는거에 초점을 맞춰보자
- type[자식] <- type[부모] 가 가능해져
- 그러면 부모에서 투상화시켜 처리할 수 있는 로직을 자식에게 부여할 수 있음
abstract class Serializer[-A] { def serialize(a: A): String } val animalSerializer: Serializer[Animal] = new Serializer[Animal] { override def serialize(animal: Animal): String = s"""{ "name": "${animal.name}" }""" } val catSerializer: Serializer[Cat] = animalSerializer catSerializer.serialize(cat("Felix"))
Upper Type Bounds & Lower Type Bounds¶
- Upper Type Bounds
- 자바 제네릭 extends 와 비슷
abstract class Animal { def name: string } abstract class Pet extends Animal {} class Cat extends Pet { override def name: String = "Cat" } class Dog extends Pet { override def name: String = "Dog" } class Lion extends Animal { override def name: String = "Lion" } class PetContainer[P <: Pet](p: P) { def pet: P = p } val dogContainer = new PetContainer[Dog](new Dog) val catContainer = new PetContainer[Cat](new Cat) val lionContainer = new PetContainer[Lion](new Lion) // 이딴거 안대! Animal 상속이여
- 자바 제네릭 extends 와 비슷
- Lower Type Bounds
- 자바 제네릭 super 와 비슷
trait Bird case class AfricanSwallow() extends Bird case class EuropeanSwallow() extends Bird val africanSwallow: List[AfricanSwallow] = Nil.prepend(AfricanSwallow()) val swallowsFromAntarctica: List[Bird] = Nil val someBird: Bird = EuropeanSwallow() val birds: List[Bird] = africanSwallows val someBirds = africanSwallow.prepend(someBird) val moreBirds = birds.prepend(EuropeanSwallow()) val allBirds = africanSwallow.prepend(EuropeanSwallow()) val error = moreBirds.prepend(swallowsFromAntarctica)
- 자바 제네릭 super 와 비슷
내부 클래스¶
- 개요
- 독특한 건 내부 클래스가 외부 클래스에 따라 별도의 타입으로 정의됨
- 인스턴스에 한정된 개념
- 자바처럼 쓰려면
외부클래스#내부클래스처럼 타입 정의하면 가능
- 자바처럼 쓰려면
- 예시
class Graph { class Node { var connectedNodes: List[Node] = nNil def connectTo(node: Node): Unit = { if (!connectedNodes.exists(node.equals)) { connectedNodes = node :: connectedNodes } } } var nodes: List[Node] = Nil def newNode: Node = { val res = new Node nodes = res :: nodes res } } val graph1: Graph = new Graph val node1: graph1.Node = graph1.newNode val node2: graph1.Node = graph1.newNode val node3: graph1.Node = graph1.newNode node1.connectTo(node2) node3.connectTo(node1) val graph2: Graph = new Graph val node3: graph2.Node = graph2.newNode node1.connectTo(node3) // 안대!!!!
추상 타입 멤버¶
trait Buffer {
type T
val element: T
}
abstract class SeqBuffer extends Buffer {
type U
type T <: Seq[U]
def length = element.length
}
abstract class IntSeqBuffer extends SeqBuffer {
type U = Int
}
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
type T = List[U]
val element = List(elem1, elem2)
}
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
합성 타입¶
- 객체의 타입을 여러 다른 타입의 서브 타입으로 표현해야 하는 경우
- 합성 타입으로 이를 표현할 수 있음 (객체 타입들의 교차점) with
Cloneable,Resetabletrait Cloneable extends java.lang.Cloneable { override def clone(): Cloneable = { super.clone().asInstanceOf[Cloneable] } } trait Resetable { def reset: Unit } // 클론하고 리셋할 수 있는 객체를 넘겨 받고 싶다면 이런식으로... def cloneAndReset(obj: Cloneable with Resetable): Cloneable = { val cloned = obj.clone() obj.reset cloned }
셀프 타입¶
- 어렵네...
- 어떤 trait를 확장해서 쓰려할 때 다른 trait도 가져와서 사용해야해를 강제하는 것
묵시적 파라미터¶
- 개요
- 메서드에 파라미터 전달해 호출할 때,
- 반복 전달하는 파라미터를 자동으로 전달
- 타입에 따라 다양한 파라미터를 자동으로 전달
implicit키워드를 기반으로 생략되어있는 파라미터를 뚝딱 찾아서 전달 할 수 있음
- 예시
abstract class Monoid[A] { def add(x:A, y:A): A def unit: A } implicit val stringMonoid: Monoid[String] = new Monoid[String] { def add(x: String, y: String): String = x concat y def unit: String = "" } implicit val intMonoid: Monoid[Int] = new Monoid[Int] { def add(x: Int, y: Int): Int = x + y def unit: Int = 0 } def sum[A](xs: List[A])(implicit m: Monoid[A]): A = if (xs.isEmpty) m.unit else m.add(xs.head, sum(xs.tail)) // 컴파일러가 은근 슬쩍 implicit 지정된 놈으로 후루룩뚝딱 알려줌 println(sum(List(1, 2, 3))) // 6 println(sum(List("a", "b", "c"))) // abc
묵시적 변환¶
- 개요
- 타입 S -> 타입 T로 자동 변환
- 식의 타입이 S 인데, 기대타입이 T인 경우,
- S => T 형태의 함수가 implicit 값을 있는 걸 사용
- 스칼라가 몰래몰래 형 변환 필요할 때 쓱 해버림
- 예시
타입 추론¶
- 컴파일러가 타입 때려 맞춰줌
- 리턴할 친구가 너무 명확하면 타입 안써줘도 됨
- 동적 언어 마냥 그냥 쓸 수 있지만, 언어적 차원에서 엄한거 넘기면 컴파일 에러!
- 너무 확정적인걸로 하면 변경하기 좀 어려울 수 있음