加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何为隐式方法实现中间类型?

发布时间:2020-12-16 10:08:00 所属栏目:安全 来源:网络整理
导读:假设我想在我控制之外的现有类型A上提供方法foo.据我所知,在 Scala中执行此操作的规范方法是实现从A到实现foo的某种类型的隐式转换.现在我基本上看到两个选项. 为此目的定义一个单独的,甚至是隐藏的类: protected class Fooable(a : A) { def foo(...) = {
假设我想在我控制之外的现有类型A上提供方法foo.据我所知,在 Scala中执行此操作的规范方法是实现从A到实现foo的某种类型的隐式转换.现在我基本上看到两个选项.

>为此目的定义一个单独的,甚至是隐藏的类:

protected class Fooable(a : A) {
  def foo(...) = { ... }
}
implicit def a2fooable(a : A) = new Fooable(a)

>定义内联匿名类:

implicit def a2fooable(a : A) = new { def foo(...) = { ... } }

变体2)肯定是较少的样板,特别是当发生许多类型参数时.另一方面,我认为它应该创建更多的开销,因为(概念上)每个转换创建一个类,而不是1)中的一个全局类.

有一般指导方针吗?没有区别,因为编译器/ VM摆脱了2)的开销?

解决方法

我相信1和2被编译为相同的字节码(除了在案例2中生成的类名).
如果Fooable只存在,你可以隐式地将A转换为Fooable(并且你永远不会直接创建和使用Fooable),那么我会选择2.

但是,如果您控制A(意味着A不是您不能子类化的java库类),我会考虑使用特征而不是隐式转换来向A添加行为.

更新:
我必须重新考虑我的答案.我会使用你的代码的变体1,因为变体2结果是使用反射(Linux上的scala 2.8.1).

我编译了相同代码的这两个版本,用jd-gui将它们反编译成java,结果如下:

具有命名类的源代码

class NamedClass { def Foo : String = "foo" }

object test {
  implicit def StrToFooable(a: String) = new NamedClass 
  def main(args: Array[String]) { println("bar".Foo) }
}

匿名类的源代码

object test {
  implicit def StrToFooable(a: String) = new { def Foo : String = "foo" } 

  def main(args: Array[String]) { println("bar".Foo) }
}

使用java-gui编译和反编译为java. “named”版本生成一个NamedClass.class,它被反编译为这个java:

public class NamedClass
  implements ScalaObject
{
  public String Foo()
  {
    return "foo";
  }
}

匿名生成一个测试$$anon $1类,它被反编译为以下java

public final class test$$anon$1
{
  public String Foo()
  {
    return "foo";
  }
}

所以几乎完全相同,除了匿名是“最终”(他们显然想要更加确定你不会试图让你的方式尝试子类匿名类……)

但是在调用站点我得到了这个“命名”版本的java

public void main(String[] args) 
{ 
  Predef..MODULE$.println(StrToFooable("bar").Foo());
}

这对于匿名者来说

public void main(String[] args) { 
    Object qual1 = StrToFooable("bar"); Object exceptionResult1 = null;
    try { 
      exceptionResult1 = reflMethod$Method1(qual1.getClass()).invoke(qual1,new Object[0]); 
      Predef..MODULE$.println((String)exceptionResult1); 
      return; 
    } catch (InvocationTargetException localInvocationTargetException) { 
      throw localInvocationTargetException.getCause();
    }
  }

我用Google搜索了一下,发现others报告了同样的事情,但我还没有找到更多的见解,为什么会这样.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读