为了账号安全,请及时绑定邮箱和手机立即绑定

如何从吹 Java 代码生成 Go 代码?

如何从吹 Java 代码生成 Go 代码?

Go
RISEBY 2021-07-09 11:07:36
我想写一个Java2Go生成器,但是我发现很难表达多态性(例如:形式arg是Base类,而真正的arg是Sub类),我如何在Go中表达吹代码?class Base{    public int i;       }class Sub extends Base{   }class Test{   public static int test(Base base){          base.i = 99;          return base.i;   }   public static void main(String [] args){       Sub sub = new Sub();       System.out.println(test(sub));   }}
查看完整描述

3 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

您需要复制代码或制作调用通用实用程序函数的包装器,这基本上是疯狂的。

没有优雅的方法来执行“逐个函数翻译”。优雅的方法是用不同的方式编写程序。

Go 程序从根本上必须具有不同的结构。从多年编写面向对象的代码开始,这是一个很难改变的习惯,但是当我找到解决问题的“类似 Go”的方法时,随着时间的推移,它通常会变得更简单。

拥有适当的继承和所有似乎可以节省代码并保持整洁的东西,但是 - 至少以我的经验 - 经过多年的开发,它很容易像一团糟一样结束,或者至少很难深入挖掘,如果你还没有使用了一段时间的代码。

Go 的接口有更多的限制,但它会迫使你让事情变得更简单和更“明显”。不同类之间的分离是明确的。

也有一些优点;在您获得一些经验之后,“混合”类型比使用继承容易得多。例如,另一个“技巧”是一种类型可以满足多个接口。

如果您一直在编写面向对象的代码,那么需要一些练习来习惯新工具。我建议不要编写翻译器,而是尝试编写一些基于 Go 的工具。那一定会很好玩。:-)


查看完整回答
反对 回复 2021-07-12
?
婷婷同学_

TA贡献1844条经验 获得超8个赞

如果您的类中只有成员变量,那么您可以使用嵌入。但是,此解决方案不会扩展到您还需要类上的方法的情况,这些方法可以在子类中覆盖,因为名称冲突会阻止您的 Go 代码编译。


您可以使用 vtable 将类编译为原始内存结构(就像编译为汇编程序或 C 一样),但是您必须实现自己的垃圾收集器。假设这不是您想要的,您可以扩展 vtable 的想法以包含返回成员变量地址的方法,这将允许您使用 Go 接口作为实现 vtable 的廉价方式。这是一些代码,稍微压缩以减少样板的外观。


package main


import "fmt"


type Base struct {

    i int

}

func (b *Base) get_i() *int { return &b.i }

func NewBase() *Base { return &Base{} }


type Sub struct {

    parent Base

}

func NewSub() *Sub { return &Sub{*NewBase()} }

func (s *Sub) get_i() *int { return s.parent.get_i() }


type BaseI interface {

    get_i() *int

}


func test(b BaseI) int {

    *b.get_i() = 99

    return *b.get_i()

}


func main() {

    s := NewSub()

    fmt.Println(test(s))

}

方法需要进行名称修饰,因为 Java 允许重载。根据对象的类型和所有方法参数的类型,您会发现在给定的调用站点上确切地确定需要调用哪个方法很有趣:)


事实上,很多事情最终都需要改名。例如,上面的代码直接翻译了类名“Base”和“Sub”,但是如果我将其中一个类称为“main”,或者我将其称为“Sub”、“NewBase”(没有“ t 出现在原始 Java 源代码中,但在翻译过程中出现)?通常,翻译后的代码看起来更像这样,以避免出现这些类型的问题:


type Java_class_Base struct {

    Java_member_i Java_basetype_int

}

还有很多其他障碍。例如,上面的代码将 Java 转换int为 Go int,但两者并不相同。Go 的int32更接近,但行为仍然不同(例如,Java 指定了溢出时会发生什么,但 Go 没有)。这意味着即使是简单的表达式 likex = x + 1也很难翻译,因为您将不得不编写自己的 add 函数以确保翻译后的代码与 Java 代码的行为相同。另一个例子是每个对象都可能充当线程可重入锁(因为它可以synchronised打开)。这意味着您将不得不决定如何翻译它,这将涉及到 Java 线程的概念,并能够确定您的翻译调用正在哪个 Java 线程上执行。


祝你好运!前面有很多困难,但制作编译器是一个有趣的挑战。


查看完整回答
反对 回复 2021-07-12
  • 3 回答
  • 0 关注
  • 282 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信