【问题标题】:Scala: Avoid var or mutable typeScala:避免使用 var 或可变类型
【发布时间】:2017-01-18 22:24:17
【问题描述】:

我有一个如下所示的伪代码。 ItemChurner.churn() 是抽象组件,它生成对象直到x 次,其中x 是未知的。 :

def func: MyList = {

    var list: MyList = MyList()

    while(ItemChurner.canChurn) {
        list = new MyList(ItemChurner.churn(), list)
    }

    list
}

有没有办法避免使用var

【问题讨论】:

  • 你可以实现Iterator接口,比如val iterator = new Iterator {def hasNext = ItemChurner.canChurn; def next = ItemChurner.churn(),然后iterator.toList
  • 为什么要用 try-catch 包裹 while 循环的内部?如果没有元素,ItemChurner 不应该返回false 吗?
  • @YuvalItzchakov:对。更正了 sn-p。

标签: scala functional-programming immutability


【解决方案1】:

如果canChurn 正常工作:

def func(churner: ItemChurner) = {
  val iterator = new Iterator {
    def hasNext = churner.canChurn
    def next = churner.churn()
  }
  iterator.toList
}

关于包含churn() 捕获的异常检查的(问题的)版本:

如果真的期待一些例外,那么canChurn 有什么意义呢?

无论如何,如果你关心异常:

 Iterator.continually(Try(churner.churn)).takeWhile(_.isSuccess).map(_.get).toList

这实际上不是很精确,因为churn 可能会抛出一些必须传播的其他异常,所以这里 scala 的Exception helpers) 就派上用场了:

def step = catching(classOf[NoMoreElementsException]) opt churner.churn()
Iterator.continually(step).takeWhile(_.nonEmpty).map(_.get).toList

【讨论】:

  • @dk12,是的。刚刚意识到,如果我有 canChurn,就不需要捕获异常。感谢您指出。问题已更新。
  • @dk12 我认为Iterator.continually(if (churner.canChurn) Some(churner.churn()) else None).takeWhile(_.isEmpty).map(_.get).toList 是更好的选择,因为它只依赖于churner 功能的暴露部分。
  • @SarveshKumarSingh 这取决于。在Try 中捕获异常可能会更慢,除了实际检查表明没有更多元素的确切异常的代码不太优雅(可能需要Exception helpers
【解决方案2】:

如果您想使用简单递归并避免使用var。这是函数式编程中使用的一般策略。

使用Vector 代替List 有效的append

def func[T](): List[T] = {

  @tailrec
  def helper(result: List[T]): List[T] = {
    if (ItemChurner.canChurn) helper(result ++ List(ItemChurner.churn))
    else result
  }

  helper(List.Empty[T])
}

假设ItemChurner.canChurn 没有抛出任何异常。如果它抛出异常,只需将其包装在 Try

【讨论】:

  • 关于有效性,List 似乎不是最佳选择,因为List ++ List 具有线性复杂性。 Vectorhas 有效常量追加
  • @dk14 你是绝对正确的。谢谢。编辑了答案。
【解决方案3】:

改进pamu的回答,你可以做一些事情;

def func: MyList = {
  def process(cur: MyList): MyList = {
    if (ItemChurner.canChurn) process(new MyList(ItemChurner.churn(), cur))
    else cur
  }
  process(new MyList())
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    • 2018-06-08
    • 2020-10-28
    • 2018-12-23
    • 2017-09-12
    • 2011-02-20
    • 2012-02-21
    相关资源
    最近更新 更多