[scala] lazy, view

scala 2016. 9. 28. 17:36


아래 값을 계산하면 당연 6이 출력된다.

var a = 3
val b = a + 3
a += 1
println(b)



스칼라에서 늦은 초기화(laziness)를 지원하며, lazy 지시자를 사용하면 호출되는 순간 값이 초기화된다.

var a = 3
lazy val b = a + 3
a += 1
println(b)


결과는 7이다.





상속 구조의 클래스에서도 사용할 수 있다. 


abstract class Parent {
val value: String
println ("value : " + value.length)
}

object Child extends Parent { lazy val value = "Hello" }



lazy를 사용하지 많으면 NPE가 발생하지만, lazy를 통해서 5라는 결과를 얻을 수 있다. 






스칼라의 lazy 언어 기능을 사용한 것이 바로 컬렉션의 view이다. 


println((1 to 3).view)
println((1 to 3).view.force)


결과는 다음과 같다.


SeqView(...)

Vector(1, 2, 3)



view메소드만 호출하면 값이 결정되지 않은 SeqView만 리턴한다.

view의 정의를 보면, 다음과 같다. lazy로 인스턴스를 그제서야 실행한다. 


override def view = new SeqView[A, Repr] {
protected lazy val underlying = self.repr
override def iterator = self.iterator
override def length = self.length
override def apply(idx: Int) = self.apply(idx)
}

컬렉션 메소드는 strict한 transformer가 있고, lazy한 transformer로 구현된 메소드로 나뉜다.  view는 이 lazy를 이용한다. '



또한, strict한 메소드를 사용하면 일련의 객체를 메모리에 계속 쌓지만, view는 함수적으로 transformer를 잘 사용한다. view를 이용하면, 메모리잘 잘 아낄 수 있다. 



scala> (1 to 1000000000).filter(_ % 2 == 0).take(10).toList

java.lang.OutOfMemoryError: GC overhead limit exceeded

  at java.lang.Integer.valueOf(Integer.java:832)

  at scala.runtime.BoxesRunTime.boxToInteger(BoxesRunTime.java:65)

  at scala.collection.immutable.Range.foreach(Range.scala:160)

  at scala.collection.TraversableLike$class.filterImpl(TraversableLike.scala:247)

  at scala.collection.TraversableLike$class.filter(TraversableLike.scala:259)

  at scala.collection.AbstractTraversable.filter(Traversable.scala:104)

  ... 26 elided


scala> (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList

res1: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)





view는 모듈이나 라이브러리, DAO 레이어 객체에서 많이 사용될 수 있다.






Posted by '김용환'
,