Scala编译器说,如果使用隐式和匿名类,我的方法是递归的
我希望能够像这样编写代码Scala编译器说,如果使用隐式和匿名类,我的方法是递归的,scala,dsl,anonymous-class,higher-order-functions,implicits,Scala,Dsl,Anonymous Class,Higher Order Functions,Implicits,我希望能够像这样编写代码 10 times { doSomething } 所以我想我可以用它来做 当我在Scala REPL中执行以下代码时,它得到了正确的定义 scala> implicit def intToMyRichInt(count: Int) = { | new { | def times(f: => Unit) = { | 1 to count foreach { _ => f } |
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 }
有什么区别?我做错了什么?我认为scala无法推断递归函数的返回类型,原因我曾经知道,但现在忘记了
但在您的情况下,我可以成功编译该文件,除非它再错过一个} 通过删除def的{修复代码后,它编译得很好:
scala> object Test {
| implicit def intToMyRichInt(count: Int) = {
| new {
| def times(f: => Unit) =
| 1 to count foreach { _ => f }
| }
| }
| }
defined module Test
还建议删除隐式定义后面的{}:
object Test {
implicit def intToMyRichInt(count: Int) =
new {
def times(f: => Unit) =
1 to count foreach { _ => f }
}
}
另外,值得一提的是,新的{…class content…}实际上是编译器的一种结构类型,因此对times的调用将进行反射。解决方法之一是创建一个新类:
object Test {
class MyRichInt(x:Int) {
def times(f: => Unit) = 1 to x foreach { _ => f }
}
implicit def intToMyRichInt(count: Int) = new MyRichInt(count)
}
希望已经回答了您的问题。不幸的是,pedrofurla建议的解决方案似乎不起作用(至少在2.8.0决赛中是这样):
对象测试{
隐式def intomyrichint(计数:Int)=
新ScalaObject{
def次数(f:=>单位)=
1来计算每个{{u0=>f}
}
def foo=10.5倍{println(“foo”)}
}
F:\MyProgramming\raw>scalac-Xprint:jvm Main.scala
[[jvm末尾的语法树]]//Scala源代码:Main.Scala
包装{
最后一个类测试使用ScalaObject扩展了java.lang.Object{
最终私有变量reflParams$Cache1:Array[java.lang.Class]=Array[java.lang.Class]{classOf[scala.Function0]};
@volatile private var reflPoly$Cache1:java.lang.ref.SoftReference=new java.lang.ref.SoftReference(new scala.runtime.EmptyMethodCache());
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))
返回方法1
其他的
{
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));
返回方法1
}
};
隐式def intToMyRichInt(count$1:Int):ScalaObject=newtest$$anon$1(count$1);
def foo():单位={
{
val qual1:ScalaObject=Test.this.intomyrichint(10);
{
{
var exceptionResult1:java.lang.Object=\uU4;
试一试{
exceptionResult1=Test.reflMethod$Method1(qual1.getClass()).invoke(qual1,数组[java.lang.Object]{{
(新测试$$anonfun$foo$1():函数0)
}})
}抓住{
case($1$@(551;:java.lang.reflect.InvocationTargetException))=>{
exceptionResult1=抛出$1$.getCause()
}
};
例外结果1
};
scala.runtime.BoxedUnit.UNIT
}
};
()
};
def this():对象测试={
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最终类测试$$anon$1$$anonfun*$1扩展了scala.runtime.AbstractFunction1$mcVI$sp{
最终def应用(x$1:Int):单位=测试$$anon$1$$anonfun*$1。此。应用$mcVI$sp(x$1);
def apply$mcVI$sp(v1:Int):Unit=Test$$anon$1$$anonfun*$1.f$1.apply$mcV$sp();
最终定义应用(v1:java.lang.Object):java.lang.Object={
Test$$anon$1$$anonfun*$1.this.apply(scala.Int.unbox(v1));
scala.runtime.BoxedUnit.UNIT
};
private[this]val f$1:Function0=\u0;
定义此($outer:Test$$anon$1,f$1:Function0):Test$$anon$1$$anonfun*$1={
测试$$anon$1$$anonfun*$1。此.f$1=f$1;
Test$$anon$1$$anonfun*$1.super.this();
()
}
};
最终类测试$$anon$1使用ScalaObject扩展了java.lang.Object{
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({
(新测试$$anon$1$$anonfun*$1(测试$$anon$1.this,f$1):功能1)
});
private[this]val count$1:Int=\;
定义此(计数$1:Int):测试$$anon$1={
Test$$anon$1。this.count$1=count$1;
Test$$anon$1.super.this();
()
}
};
@SerialVersionUID(0)@serializable最终类测试$$anonfun$foo$1扩展了scala.runtime.AbstractFunction0$mcV$sp{
final def apply():Unit=Test$$anonfun$foo$1.this.apply$mcV$sp();
def apply$mcV$sp():Unit=scala.this.Predef.println(“foo”);
final 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();
()
}
}
}
@tbruhn:我无法验证您的问题,它在这里编译得很好
我怀疑您使用的是一些过时的Scala版本,可能吧
如果是这样的话,显而易见的修复方法是升级到Scala 2.8.x
否则,如何编译?如果您是通过IDE编译,请尝试查看scalac
是否存在相同的错误。编译器无法推断递归函数/方法的结果类型。推断取决于结果表达式的类型。在递归函数中,结果表达式通常是函数本身如果,在这种情况下,如果还不知道该类型如何推断?但正如@the_great_monkey所指出的,问题并非如此。我最初很兴奋,但这
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();
()
}
}
}