Scala是否与C#yield相当?

Ale*_*ack 24 c# scala yield

我是Scala的新手,据我所知,Scala中的收益与C#中的收益不同,它更像是选择.

Scala有类似于C#的收益吗?C#的收益很好,因为它使编写迭代器变得非常容易.

更新:这是来自C#的伪代码示例,我希望能够在Scala中实现:

public class Graph<T> {
   public IEnumerable<T> BreadthFirstIterator() {
      List<T> currentLevel = new List<T>();
      currentLevel.add(_root);

      while ( currentLevel.count > 0 ) {
         List<T> nextLevel = new List<T>();
         foreach( var node in currentLevel ) {
            yield return node;
            nextLevel.addRange( node.Children );
         }
         currentLevel = nextLevel;
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

此代码实现了图的迭代广度优先遍历,使用yield,它返回一个迭代器,以便调用者可以使用常规for循环遍历图,例如:

graph.BreadthFirstIterator().foreach( n => Console.WriteLine( n ) );
Run Code Online (Sandbox Code Playgroud)

在C#中,yield只是语法糖,可以很容易地编写迭代器(IEnumerable<T>在.Net中,类似于IterableJava).作为迭代器,它的评估很懒散.

更新II:我可能在这里错了,但我认为C#中的整个收益点是你不必编写更高阶函数.例如,你可以编写一个常规for循环或使用像select/ map/ filter/ 这样的方法,where而不是传入一个函数,然后遍历序列.

graph.iterator().foreach(n => println(n))代替graph.iterator( n => println(n)).

这样你可以轻松地链接它们,例如graph.iterator().map(x => x.foo).filter(y => y.bar >= 2).foreach(z => println(z)).

seh*_*seh 10

在这里劫持单词yield会分散其通常的意图:作为协程中的进入/退出标记.上例中的C#BreadthFirstIterator似乎yield在其协同感中使用; 值由返回后yield,要积极下次调用BreadthFirstIteratorIEnumerable将继续后面的语句yield.

在C#,yield耦合到迭代的想法,而不是更一般控制流语句,但该有限域中的其行为是一个协程的.Scala的分隔延续可能允许人们定义协同程序.在此之前,Scala缺乏这样的能力,特别是考虑到它的替代意义yield.

  • 我认为你已经击中了Seh头上的钉子.听起来Java正在获得本地协程,这可能会在Scala中提供它:http://weblogs.java.net/blog/forax/archive/2009/11/19/holy-crap-jvm-has-coroutinecontinuationfiber-etc (2认同)

Ale*_*ack 4

我认为答案(除非 2.8 中发生变化)答案是否定的,Scala 没有类似于 C# 的yield 的语法糖来编写迭代器(IEumerable 或 Iterable 的实现)。

然而,在 Scala 中,您可以通过向遍历传递一个函数来实现类似的结果,该函数将在遍历中的每个项目上调用该函数。这种方法也可以在 C# 中以相同的方式实现。

以下是我在 C# 中编写 Traverse 而不使用 Yield 的方法:

public class Graph<T> {
   public void BreadthFirstTraversal( Action<T> f) {
      List<T> currentLevel = new List<T>();
      currentLevel.add(_root);

      while ( currentLevel.count > 0 ) {
         List<T> nextLevel = new List<T>();
         foreach( var node in currentLevel ) {
            f(node);
            nextLevel.addRange( node.Children );
         }
         currentLevel = nextLevel;
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

graph.BreadthFirstTraversal( n => Console.WriteLine( n ) );
Run Code Online (Sandbox Code Playgroud)

或者像这样:

graph.BreadthFirstTraversal( n =>
{
   Console.WriteLine(n);
   DoSomeOtherStuff(n);
});
Run Code Online (Sandbox Code Playgroud)

  • 当然,使用 C# 的产量会更直观。 (4认同)
  • 而且你也不能以这种方式链接调用,如:graph.BreadthFirstTraversal().Where(...)。 (2认同)