通过字符串返回步骤来实现河内塔的有效方法

I'm comparing several algorithms in JS, Rust and Go. I implemented Towsers of Hanoi this way in Go:

func Hanoi() (hanoi func(n int, from, via, to string) string) {
    var moves strings.Builder
    var hanoiRe func(n int, from, via, to string)
    hanoiRe = func(n int, from, via, to string) {
        if n > 0 {
            hanoiRe(n-1, from, to, via)
            moves.WriteString(from)
            moves.WriteString("->")
            moves.WriteString(to)
            moves.WriteString("
")
            hanoiRe(n-1, via, from, to)
        }
    }
    hanoi = func(n int, from, via, to string) string {
        hanoiRe(n, from, via, to)
        return moves.String()
    }
    return
}

But this implementation is much slower than JS or Rust. So I think, this could be done faster. But how?

I already tried type hanoi struct{moves strings.Builder} with func (h *hanoi) ..., which is a bit slower. The way using a string and moves += ...is much slower.

EDIT:

My comparisons:

JS:

class HanoiJS {
    constructor() {
        this.moves = "";
    }
    hanoi(n, from, via, to) {
        if (n > 0) {
            this.hanoi(n - 1, from, to, via);
            this.moves += from + "->" + to + "
";
            this.hanoi(n - 1, via, from, to);
        }
        return this.moves;
    }
}

Rust:

pub struct Hanoi {
    moves: String
}

impl Hanoi {

    pub fn new() -> Hanoi {
        Hanoi {
            moves: String::new()
        }
    }

    pub fn hanoi(&mut self, n: i32, from: &str, via: &str, to: &str) -> &str {
        if n > 0 {
            self.hanoi(n - 1, from, to, via);
            self.moves.push_str(from);
            self.moves.push_str("->");
            self.moves.push_str(to);
            self.moves.push_str("
");
            self.hanoi(n - 1, via, from, to);
        }
        return &self.moves;
    }
}

Compared with n=20 and 5 times: chart