3 回答
TA贡献1799条经验 获得超9个赞
您需要复制代码或制作调用通用实用程序函数的包装器,这基本上是疯狂的。
没有优雅的方法来执行“逐个函数翻译”。优雅的方法是用不同的方式编写程序。
Go 程序从根本上必须具有不同的结构。从多年编写面向对象的代码开始,这是一个很难改变的习惯,但是当我找到解决问题的“类似 Go”的方法时,随着时间的推移,它通常会变得更简单。
拥有适当的继承和所有似乎可以节省代码并保持整洁的东西,但是 - 至少以我的经验 - 经过多年的开发,它很容易像一团糟一样结束,或者至少很难深入挖掘,如果你还没有使用了一段时间的代码。
Go 的接口有更多的限制,但它会迫使你让事情变得更简单和更“明显”。不同类之间的分离是明确的。
也有一些优点;在您获得一些经验之后,“混合”类型比使用继承容易得多。例如,另一个“技巧”是一种类型可以满足多个接口。
如果您一直在编写面向对象的代码,那么需要一些练习来习惯新工具。我建议不要编写翻译器,而是尝试编写一些基于 Go 的工具。那一定会很好玩。:-)
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 线程上执行。
祝你好运!前面有很多困难,但制作编译器是一个有趣的挑战。
- 3 回答
- 0 关注
- 282 浏览
添加回答
举报