Programming in Sala 책으로 스칼라 스터디하면서 정리했던 내용이다. 지금은 3판 번역본도 나왔지만, 약간 앞서서 스터디를 시작해서 2판으로 진행했다.
18장
변경 가능한 상태
- 순수 함수형은 변경 가능한 상태가 없음.
var
이 있더라도 캐시 등의 용도라면 순수 함수형일 수 있음.var
이 없더라도 변경 가능한 상태를 가진 다른 객체에게 호출을 위임하면서 변경 가능한 상태를 가질 수 있음.
재할당 가능한 변수
- 비공개가 아닌 모든
var
멤버에 게터/세터 메소드를 자동으로 정의함. var x
의 게터는x
, 세터는x_=
- 게터와 세터는 원래
var
과 같은 가시성을 가지고, 필드는private[this]
가 붙음
class Time {
var hour = 12
var minute = 0
}
// 실제 자동 확장
class Time {
private[this] hour = 12
private[this] minute = 0
def hour: Int = h
def hour_= (x: Int) { h = x }
def minute: Int = m
def minute_= (x: Int) { m = x }
}
// 직접 정의
class Time {
private[this] hour = 12
private[this] minute = 0
def hour: Int = h
def hour_= (x: Int) {
require(0 <= x && x < 24)
}
def minute: Int = m
def minute_= (x: Int) {
require(0 <= x && x < 60)
m = x
}
}
- 연관된 필드 없이 게터/세터 정의
class Thermometer {
var celsius: Float = _ // 초기화 값.
def fahrenheit = celsius * 9 / 5 + 32
def fahrenheit_= (f: Float) {
celsius = (f - 32) * 5 / 9
}
override def toString = fahrenheit +"F/"+ celsius +"C"
}
- 필드 초기화 값
- 수 타입 : 0
- 불리언 타입 : false
- 레퍼런스 타입 : null
= _
초기화를 생략하면 추상 변수(20장)를 선언함
예 : 이산 이벤트 시뮬레이션
package org.stairwaybook.simulation
abstract class Simulation {
type Action = () => Unit
case class WorkItem(time: Int, action: Action)
private var curtime = 0
def currentTime: Int = curtime
private var agenda: List[WorkItem] = List()
private def insert(ag: List[WorkItem], item: WorkItem): List[WorkItem] = {
if (ag.isEmpty || item.time < ag.head.time) item :: ag
else ag.head :: insert(ag.tail, item)
}
def afterDelay(delay: Int)(block: => Unit) {
val item = WorkItem(currentTime + delay, () => block)
agenda = insert(agenda, item)
}
private def next() {
(agenda: @unchecked) match {
case item :: rest =>
agenda = rest
curtime = item.time
item.action()
}
}
def run() {
afterDelay(0) {
println("*** simulation started, time = "+ currentTime +" ***")
}
while (!agenda.isEmpty) next()
}
}
abstract class BasicCircuitSimulation extends Simulation {
def InverterDelay: Int
def AndGateDelay: Int
def OrGateDelay: Int
class Wire {
private var sigVal = false
private var actions: List[Action] = List()
def getSignal = sigVal
def setSignal(s: Boolean) {
if (s != sigVal) {
sigVal = s
actions foreach (_ ())
}
}
def addAction(a: Action) {
actions = a :: actions
a()
}
}
def inverter(input: Wire, output: Wire) {
def invertAction() {
val inputSig = input.getSignal
afterDelay(InverterDelay) {
output setSignal !inputSig
}
}
input addAction invertAction
}
def andGate(a1: Wire, a2: Wire, output: Wire) {
def andAction() = {
val a1Sig = a1.getSignal
val a2Sig = a2.getSignal
afterDelay(AndGateDelay) {
output setSignal (a1Sig & a2Sig)
}
}
a1 addAction andAction
a2 addAction andAction
}
def orGate(o1: Wire, o2: Wire, output: Wire) {
def orAction() {
val o1Sig = o1.getSignal
val o2Sig = o2.getSignal
afterDelay(OrGateDelay) {
output setSignal (o1Sig | o2Sig)
}
}
o1 addAction orAction
o2 addAction orAction
}
def probe(name: String, wire: Wire) {
def probeAction() {
println(name +" "+ currentTime +" new-value = "+ wire.getSignal)
}
wire addAction probeAction
}
}
abstract class CircuitSimulation extends BasicCircuitSimulation {
def halfAdder(a: Wire, b: Wire, s: Wire, c: Wire) {
val d, e = new Wire
orGate(a, b, d)
andGate(a, b, c)
inverter(c, e)
andGate(d, e, s)
}
def fullAdder(a: Wire, b: Wire, cin: Wire, sum: Wire, cout: Wire) {
val s, c1, c2 = new Wire
halfAdder(a, cin, s, c1)
halfAdder(b, s, sum, c2)
orGate(c1, c2, cout)
}
}
import org.stairwaybook.simulation._
object MySimulation extends CircuitSimulation {
def InverterDelay = 1
def AndGateDelay = 3
def OrGateDelay = 5
}
import MySimulation._
val input1, input2, sum, carry = new Wire
probe("sum", sum)
probe("carry", carry)
halfAdder(input1, input2, sum, carry)
input1 setSignal true
run()
input2 setSignal true
run()
'Developing' 카테고리의 다른 글
Programming in Scala 스터디 정리 - 19장. 타입 파라미터화 (0) | 2017.10.01 |
---|---|
Programming in Scala 스터디 정리 - 17장. 컬렉션 (0) | 2017.09.28 |
Programming in Scala 스터디 정리 - 16장. 리스트 (0) | 2017.09.26 |