3

我希望能够编写类似的代码

10 times {
   doSomething
}

所以我想我可以用隐式来做到这一点。

当我在 Scala REPL 中执行以下代码时,它被正确定义

scala> implicit def intToMyRichInt(count: Int) = {
    |     new {
    |       def times(f: => Unit) = {
    |         1 to count foreach { _ => f }
    |       }
    |     }
    |   }

但是,当我尝试编译时,

object Test {
    implicit def intToMyRichInt(count: Int) = {
      new {
        def times(f: => Unit) = {
           1 to count foreach { _ => f }
      }
   }
}

它失败并出现错误

error: recursive method intToMyRichInt needs result type
1 to count foreach { _ => f }

有什么区别?我究竟做错了什么?

4

4 回答 4

2

通过删除 def 的 { 修复代码后,它编译得很好:

scala> object Test {
     |     implicit def intToMyRichInt(count: Int) = {
     |       new {
     |         def times(f: => Unit) =
     |            1 to count foreach { _ => f }
     |       }
     |    }
     | }
defined module Test

还建议在隐式 def 之后删除 {}:

object Test {
    implicit def intToMyRichInt(count: Int) = 
      new {
        def times(f: => Unit) = 
           1 to count foreach { _ => f }
      }   
}

此外,值得一提的是,新的 { ... class content ... } 实际上是编译器的结构类型,因此对时间的调用将被反射性地进行。一种解决方法是创建一个新类:

object Test {
    class MyRichInt(x:Int) {
      def times(f: => Unit) =  1 to x foreach { _ => f }
    }
    implicit def intToMyRichInt(count: Int) = new MyRichInt(count)
}

希望已经回答了你的问题。

于 2010-10-23T02:24:57.777 回答
1

@tbruhn:我无法验证您的问题,它在这里编译得很好。

我怀疑您可能正在使用一些过时的 Scala 版本?

如果是这种情况,显而易见的解决方法是升级到 Scala 2.8.x!

不然怎么编译?如果您是通过 IDE 编译,请尝试查看是否scalac有相同的错误。

于 2010-10-23T09:35:04.510 回答
0

我认为由于我曾经知道但现在忘记的原因,scala 将无法推断递归函数的返回类型。

但在你的情况下,我可以成功编译该文件,但它又错过了一个}。

于 2010-10-22T22:58:28.503 回答
0

不幸的是,pedrofurla 建议的解决方法似乎不起作用(至少在 2.8.0 最终版本中):

object Test {
    implicit def intToMyRichInt(count: Int) = 
      new ScalaObject {
        def times(f: => Unit) = 
           1 to count foreach { _ => f }
      }

    def foo = 10.times { println("foo") }
}

F:\MyProgramming\raw>scalac -Xprint:jvm Main.scala
[[syntax trees at end of jvm]]// Scala source: Main.scala
package <empty> {
  final class Test extends java.lang.Object with ScalaObject {
    final private <synthetic> <static> var reflParams$Cache1: Array[java.lang.Class] = Array[java.lang.Class]{classOf[scala.Function0]};
    @volatile private <synthetic> <static> var reflPoly$Cache1: java.lang.ref.SoftReference = new java.lang.ref.SoftReference(new scala.runtime.EmptyMethodCache());
    <synthetic> <static> def reflMethod$Method1(x$1: java.lang.Class): java.lang.reflect.Method = {
      if (Test.reflPoly$Cache1.get().$asInstanceOf[scala.runtime.MethodCache]().eq(null))
        Test.reflPoly$Cache1 = new java.lang.ref.SoftReference(new scala.runtime.EmptyMethodCache());
      var method1: java.lang.reflect.Method = Test.reflPoly$Cache1.get().$asInstanceOf[scala.runtime.MethodCache]().find(x$1);
      if (method1.ne(null))
        return method1
      else
        {
          method1 = x$1.getMethod("times", Test.reflParams$Cache1);
          Test.reflPoly$Cache1 = new java.lang.ref.SoftReference(Test.reflPoly$Cache1.get().$asInstanceOf[scala.runtime.MethodCache]().add(x$1, method1));
          return method1
        }
    };
    implicit def intToMyRichInt(count$1: Int): ScalaObject = new Test$$anon$1(count$1);
    def foo(): Unit = {
      {
        val qual1: ScalaObject = Test.this.intToMyRichInt(10);
        {
          {
            var exceptionResult1: java.lang.Object = _;
            try {
              exceptionResult1 = Test.reflMethod$Method1(qual1.getClass()).invoke(qual1, Array[java.lang.Object]{{
                (new Test$$anonfun$foo$1(): Function0)
              }})
            } catch {
              case ($1$ @ (_: java.lang.reflect.InvocationTargetException)) => {
                exceptionResult1 = throw $1$.getCause()
              }
            };
            exceptionResult1
          };
          scala.runtime.BoxedUnit.UNIT
        }
      };
      ()
    };
    def this(): object Test = {
      Test.reflParams$Cache1 = Array[java.lang.Class]{classOf[scala.Function0]};
      Test.reflPoly$Cache1 = new java.lang.ref.SoftReference(new scala.runtime.EmptyMethodCache());
      Test.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anon$1$$anonfun*$1 extends scala.runtime.AbstractFunction1$mcVI$sp {
    final def apply(x$1: Int): Unit = Test$$anon$1$$anonfun*$1.this.apply$mcVI$sp(x$1);
    <specialized> def apply$mcVI$sp(v1: Int): Unit = Test$$anon$1$$anonfun*$1.this.f$1.apply$mcV$sp();
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = {
      Test$$anon$1$$anonfun*$1.this.apply(scala.Int.unbox(v1));
      scala.runtime.BoxedUnit.UNIT
    };
    <synthetic> <paramaccessor> private[this] val f$1: Function0 = _;
    def this($outer: Test$$anon$1, f$1: Function0): Test$$anon$1$$anonfun*$1 = {
      Test$$anon$1$$anonfun*$1.this.f$1 = f$1;
      Test$$anon$1$$anonfun*$1.super.this();
      ()
    }
  };
  final class Test$$anon$1 extends java.lang.Object with ScalaObject {
    def times(f$1: Function0): Unit = scala.this.Predef.intWrapper(1).to(Test$$anon$1.this.count$1).$asInstanceOf[scala.collection.immutable.Range$ByOne]().foreach$mVc$sp({
      (new Test$$anon$1$$anonfun*$1(Test$$anon$1.this, f$1): Function1)
    });
    <synthetic> <paramaccessor> private[this] val count$1: Int = _;
    def this(count$1: Int): Test$$anon$1 = {
      Test$$anon$1.this.count$1 = count$1;
      Test$$anon$1.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$foo$1 extends scala.runtime.AbstractFunction0$mcV$sp {
    final def apply(): Unit = Test$$anonfun$foo$1.this.apply$mcV$sp();
    <specialized> def apply$mcV$sp(): Unit = scala.this.Predef.println("foo");
    final <bridge> def apply(): java.lang.Object = {
      Test$$anonfun$foo$1.this.apply();
      scala.runtime.BoxedUnit.UNIT
    };
    def this(): Test$$anonfun$foo$1 = {
      Test$$anonfun$foo$1.super.this();
      ()
    }
  }
}
于 2010-10-23T05:43:41.670 回答