需要 Scala 函数体定义帮助

Scala function body definition help wanted

我正在尝试使用以下语法制作 scala dsl:

val a = Agent() setup { agent => // agent reference.
  agent add "Hello World!"
}
a add "Not allowed" // Atm this is allowed.

我可以在设置函数体之外调用方法 add 并调用 add 方法我必须在设置函数体的开头写 agent =>

我在atm做过的是trait Agent:

trait Agent {

  def setup(f: Agent => Unit): Agent

  def add(s: String): Agent
}

case class AgentImpl(strings: Seq[String]) extends Agent {
  override def setup(f: Agent => Unit): Agent = {
    f(this)
    this
  }

  override def add(s: String): Agent = copy(strings = strings:+s)
}

object Agent {
  def apply(): Agent = AgentImpl(Seq.empty)
}

我要做的是:

val a = Agent() setup { // No more references to agent
    add "Hello World!"
  }
  a add "Not allowed" // This mustn't be allowed. Compilation error.

在设置函数主体的开头我没有使用 agent => 引用代理,如果我尝试在设置函数主体之外进行添加,我会收到错误消息。

这在 Scala 中可行吗?

我可以更改代码的每一部分,添加任意数量的 traits/classes/objects 和其他内容,但不能更改我的 DSL 的语法。

你可以这样做:

sealed trait Agent {
  def getFoos: List[String]
  def getBars: List[Int]
}

object Agent {
  import scala.collection.mutable.ListBuffer
  
  private final class Builder {
    private[this] val foos: ListBuffer[String] = ListBuffer.empty
    private[this] val bars: ListBuffer[Int] = ListBuffer.empty
    
    private def addFoo(foo: String): Unit = {
      foos += foo
    }
    
    private def addBar(bar: Int): Unit = {
      bars += bar
    }
    
    private[Agent] def result(): Agent = new Agent {
      override final val getFoos: List[String] =
        foos.result()
      
      override final val getBars: List[Int] =
        bars.result()
    }
  }
  
  private[Agent] type BuilderStep = Builder => Unit
  
  object Builder {
    private[Agent] def create() = new Builder()
    
    object Steps {
      def addFoo(foo: String): BuilderStep =
        _.addFoo(foo)
      
      def addBar(bar: Int): BuilderStep =
        _.addBar(bar)
    }
  }
  
  def setup(steps: BuilderStep*): Agent = {
    val builder = Builder.create()
    steps.foreach(s => s(builder))
    builder.result()
  }
}

可以这样使用:

import Agent.Builder.Steps._

val agent = Agent.setup(
  addFoo("A"),
  addFoo("B"),
  addBar(1),
  addBar(2),
  addFoo("C"),
  addBar(3),
  addFoo("D")
)

但也许传统的不可变构建器同样好用且更简单。


代码运行here.