Skip to content

Proposal: TemplateRecvMethod

xushiwei edited this page Jun 19, 2026 · 2 revisions

我们知道,在 Go 语言的类型中并没有虚函数的概念,所以我们不能在基类中抽象某个方法让派生类去实现它以实现多态。例如,在 C++ 中我们可以:

class Game {
public:
   virtual void OnDraw() = 0;
   void Run() { ... }
}

class MyGame : public Game {
    void OnDraw() { ... }
}

在 Go 中我们只能这样做:

type Drawer interface {
    OnDraw()
}

type Game struct {
    drawer Drawer
    ...
}

func (g *Game) SetDrawer(drawer Drawer) {
    g.drawer = drawer
}

func (g *Game) Run() {
    ...
}

type MyGame struct {
    Game
    ...
}

func NewMyGame() *MyGame {
    g := new(MyGame)
    g.SetDrawer(g)
    ...
    return g
}

func (g *MyGame) OnDraw() { ... }

整体来说,Go 通过 interface 实现多态利大于弊。但是对于这种情况下框架的使用者来说确实会显得有点麻烦。为此 XGo 考虑引入 Template Recv Method 概念来解决。

什么是 Template Recv Method?我们看一下如下 “伪 XGo 代码”:

type Game struct {
    ...
}

func [g *Game] OnDraw() { ... }
func [T Game] (g *T) Run() { ... }

type MyGame struct {
    Game
    ...
}

func (g *MyGame) OnDraw() { ... }

注意这一行:

func [T Game] (g *T) Run() { ... }

它不是 XGo 的语法,只是表达了这样一种语义:这是一个 template method,并且不是 method arguments 是 template,而是 receiver 类型 T 是 template,它必须聚合(用 C++ 的术语是派生)了 Game 类。这样当我们调用:

var g Game
g.Run() // T = Game

var g MyGame
g.Run() // T = MyGame

这就让 Run 方法具备了多态的能力:虽然 OnDraw() 不是虚函数,但是 Run() 函数在调用它的时候调用到了具体的 receiver 类型对应的 OnDraw 函数。

但是 XGo 没有 Template Recv Method 语法怎么办?

Go Is XGo's "Assembly Language"

That framing sounds bold, but it is precise. XGo does not treat Go as a mere transport medium the way some "compiles-to-Go" languages do. XGo treats Go as its semantic foundation:

  • Every XGo package can be translated one-to-one into a Go package.
  • The translated Go package preserves semantics exactly and can be consumed by any standard Go toolchain.
  • Conversely, that translated Go package can also be imported by other XGo code, with no bridging layer required.

This means XGo's type system, memory model, and concurrency primitives are all inherited directly from Go. Go's compiler-level verification applies uniformly to all XGo source — no exceptions, no carve-outs.

基于此,我们不定义 XGo 语法,而是先定义 Template Recv Method 在 Go 里面应该长什么样。

type gamer interface {
    ... // Any methods that indicates this is a Game, such as OnDraw()
}

func XGot_Game_Run[T gamer](g gamer) { ... }

我们用 XGot_ 前缀表示这是一个 Template Recv Method,并且把 receiver 挪到右侧作为函数的第一个参数。这样,汇编版本的 Template Recv Method 就有了。

Clone this wiki locally