代码之家  ›  专栏  ›  技术社区  ›  bsdfish

scala中编译时对象创建的语法糖

  •  4
  • bsdfish  · 技术社区  · 15 年前

    让我说我有

    trait fooTrait[T] {
      def fooFn(x: T, y: T) : T 
    }
    

    我希望使用户能够使用自己为foofn定义的主体快速声明footrait的新实例。理想情况下,我想要

    val myFoo : fooTrait[T] = newFoo((x:T, y:T) => x+y) 
    

    工作。但是,我不能这么做

    def newFoo[T](f: (x:T, y:T) => T) = new fooTrait[T] { def fooFn(x:T, y:T):T = f(x,y); }
    

    因为它使用闭包,所以当程序多次运行时会产生不同的对象。什么我 真的? 需要的是能够获取newfoo返回的对象的类,然后在另一台机器上进行构造。我该怎么办?

    如果您对用例感兴趣,我将尝试为Hadoop编写一个scala包装器,它允许您执行

    IO("Data") --> ((x: Int, y: Int) => (x, x+y)) --> IO("Out")
    

    中间的东西需要变成一个实现特定接口的类,然后可以在不同的机器上实例化(执行相同的JAR文件),只使用类名。

    请注意,scala对将(x:int)=>x+5转换为函数1实例的语法结构做了正确的处理。我的问题是我是否可以在不破坏scala内部结构的情况下复制它。如果这是lisp(就像我习惯的那样),这将是一个微不足道的编译时宏…嗅:

    2 回复  |  直到 15 年前
        1
  •  2
  •   Mitch Blevins    15 年前

    这里有一个版本,它匹配您在问题中列出的语法,并序列化/执行anon函数。请注意,这将序列化函数2对象的状态,以便可以在另一台计算机上还原序列化版本。只是类名不够,如下面的解决方案所示。

    如果仅仅包括自己的base64实现(而不是依赖于Sun的热点),那么您应该创建自己的编码/解码功能。

    object SHadoopImports {
        import java.io._
    
        implicit def functionToFooString[T](f:(T,T)=>T) = {
            val baos = new ByteArrayOutputStream()
            val oo = new ObjectOutputStream(baos)
            oo.writeObject(f)
            new sun.misc.BASE64Encoder().encode(baos.toByteArray())
        }
    
        implicit def stringToFun(s: String) = {
            val decoder = new sun.misc.BASE64Decoder();
            val bais = new ByteArrayInputStream(decoder.decodeBuffer(s))
            val oi = new ObjectInputStream(bais)  
            val f = oi.readObject()
            new {
                def fun[T](x:T, y:T): T = f.asInstanceOf[Function2[T,T,T]](x,y)
            }
        }
    }
    
    // I don't really know what this is supposed to do
    // just supporting the given syntax
    case class IO(src: String) {
        import SHadoopImports._
        def -->(s: String) = new {
            def -->(to: IO) = {
                val IO(snk) = to
                println("From: " + src)
                println("Applying (4,5): " + s.fun(4,5))
                println("To: " + snk)
            }
        }
    }
    
    object App extends Application {
      import SHadoopImports._
    
      IO("MySource") --> ((x:Int,y:Int)=>x+y) --> IO("MySink")
      println
      IO("Here") --> ((x:Int,y:Int)=>x*y+y) --> IO("There")
    }
    
    /*
    From: MySource
    Applying (4,5): 9
    To: MySink
    
    From: Here
    Applying (4,5): 25
    To: There
    */
    

    为了让自己相信类名不足以在另一台机器上使用该函数,请考虑下面创建100个不同函数的代码。计算文件系统上的类并进行比较。

    object App extends Application {
      import SHadoopImports._
    
      for (i <- 1 to 100) {
          IO(i + ": source") --> ((x:Int,y:Int)=>(x*i)+y) --> IO("sink")
      }
    }
    
        2
  •  2
  •   Eric    15 年前

    快速建议:为什么不尝试创建一个隐式的def transforming functionn对象,将其转换为-->方法所期望的特征。

    我希望您不必为此使用任何宏!