西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网
当前位置: 主页 > 开发教程 > ruby教程 >

Scala的dynamic与Ruby的method_missing

时间:2016-04-14 20:43来源:未知 作者:好模板 点击:
在Ruby中,当一个类被调用方法未找到时,该类的method_missing(name,*args,block)方法会被自动调用,通过这个黑科技,人们在ruby上实现了各种元编程技巧. 作为一个比C++还要难的语言--Scala,它有木有

在Ruby中,当一个类被调用方法未找到时,该类的method_missing(name,*args,&block)方法会被自动调用,通过这个黑科技,人们在ruby上实现了各种元编程技巧.
作为一个比C++还要难的语言--Scala,它有木有类似的黑科技呢,作为一个运行在jvm上的语言,它又是怎么实现的呢?

介绍Dynamic实现了与method_missing几乎一样的功能.然而事实上,它们差别还是挺大的.

先写2个例子吧,分别是scala,ruby实现类似的功能.

import scala.language.dynamics
import scala.io._

object Dispatch extends Dynamic {
    def selectDynamic(name:String):String = "Call Method: " + name

    def main(args:Array[String]){
        println(Dispatch.SCALA);
        println(Dispatch.RUBY);

        val cls = Dispatch.getClass
        while(true){
            println(cls.getMethod(StdIn.readLine).invoke(null))
        }
    }   
}
class Dispatch
    def method_missing(name,*args,&block)
        puts "Call Method: "+name.to_s
    end 
end

ins = Dispatch.new
ins.SCALA
ins.RUBY
ins.send(gets) while true

都是先尝试调用SCALA和RUBY方法,再循环读取用户输入,调用以输入值为名字的方法.


运行一下~


咦,java.lang.NoSuchMethodException,没有找到方法...

到底是为什么呢?看看scala编译后的字节码把.

[shyling@archlinux:~]$ javap -c Dispatch                         16-04-14 15:36
Compiled from "dynamic.scala"
public final class Dispatch {
  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field Dispatch$.MODULE$:LDispatch$;
       3: aload_0
       4: invokevirtual #18                 // Method Dispatch$.main:([Ljava/lang/String;)V
       7: return

  public static java.lang.String selectDynamic(java.lang.String);
    Code:
       0: getstatic     #16                 // Field Dispatch$.MODULE$:LDispatch$;
       3: aload_0
       4: invokevirtual #22                 // Method Dispatch$.selectDynamic:(Ljava/lang/String;)Ljava/lang/String;
       7: areturn
}

[shyling@archlinux:~]$ javap -c Dispatch\$.class                 16-04-14 15:36
Compiled from "dynamic.scala"
public final class Dispatch$ implements scala.Dynamic {
  public static final Dispatch$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class Dispatch$
       3: invokespecial #14                 // Method "<init>":()V
       6: return

  public java.lang.String selectDynamic(java.lang.String);
    Code:
       0: new           #18                 // class scala/collection/mutable/StringBuilder
       3: dup
       4: invokespecial #19                 // Method scala/collection/mutable/StringBuilder."<init>":()V
       7: ldc           #21                 // String Call Method:
       9: invokevirtual #25                 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
      12: aload_1
      13: invokevirtual #25                 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder;
      16: invokevirtual #29                 // Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
      19: areturn

  public void main(java.lang.String[]);
    Code:
       0: getstatic     #39                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       3: aload_0
       4: ldc           #41                 // String SCALA
       6: invokevirtual #43                 // Method selectDynamic:(Ljava/lang/String;)Ljava/lang/String;
       9: invokevirtual #47                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      12: getstatic     #39                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
      15: aload_0
      16: ldc           #49                 // String RUBY
      18: invokevirtual #43                 // Method selectDynamic:(Ljava/lang/String;)Ljava/lang/String;
      21: invokevirtual #47                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      24: aload_0
      25: invokevirtual #53                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      28: astore_2
      29: getstatic     #39                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
      32: aload_2
      33: getstatic     #58                 // Field scala/io/StdIn$.MODULE$:Lscala/io/StdIn$;
      36: invokevirtual #61                 // Method scala/io/StdIn$.readLine:()Ljava/lang/String;
      39: iconst_0
      40: anewarray     #63                 // class java/lang/Class
      43: invokevirtual #67                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
      46: aconst_null
      47: iconst_0
      48: anewarray     #4                  // class java/lang/Object
      51: invokevirtual #73                 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
      54: invokevirtual #47                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      57: goto          29
}

可以看到Dispatch.SCALA仅仅是被编译器翻译成了Dispatch.selectDynamic("SCALA"),其他的并没有什么黑科技.因为jvm本身没有提供类似method_missing的方法,所以...通过反射调用不存在的方法时,会抛出NoSuchMethodException.

假如我们想在jvm更贴近实现method_missing需要怎么做呢?

好像没有特别好的办法.
例如:

  • 假如可以对反射api进行monkey_patch?
  • 户手动调用selectDynamic方法?

感觉都不如method_missing优雅啊.动态语言的优势么2333

(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容