Hey there! So, I was about to file a GitHub issue, but the prompt suggested 
checking here first to avoid duplicates. I did a quick search for 
"InvalidInitCycle" and "Invalid Init Cycle" in the history and came up 
empty, so hopefully, this is a fresh report.

I'm tinkering with building a little REPL in Go. To handle commands, I set 
up a map where the keys are the command names, and the values are structs 
containing the command's name, a short description, and the actual function 
to execute.

Now, to implement a "help" command, my first instinct was to just iterate 
over this map and print out the name and description of each command. 
However, the Go compiler threw a fit about this.

As a workaround, I came up with a bit of a convoluted solution. I created a 
closure that captures my command map. This outer function then returns 
another function, and *that* inner function finally returns the map. 
Surprisingly, the compiler was perfectly happy with this setup. It compiled 
cleanly, and the "help" command in my REPL works exactly as I intended. 
This closure trick feels a bit dirty, and I'm not entirely sure if I'm 
inadvertently creating some memory leak.

What's really puzzling me is why the compiler would object to the direct 
map iteration in the first place but be perfectly fine with this nested 
function approach. Could someone shed some light on the underlying logic 
here?

For reference, I'm using go version go1.24.2 linux/amd64.

Thanks in advance for any insights!

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/96783b30-aa66-4db4-895a-d16ce3ff4807n%40googlegroups.com.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

type cliCommand struct {
	name string
	description string
	callback func() error
}

func commandExit() error {
	fmt.Println("Closing the Pokedex... Goodbye!")
	os.Exit(0)
	return nil
}

func getCommands() func() map[string]cliCommand {
	commandRegistry := map[string]cliCommand{
		"exit": {
			name:        	"exit",
			description: 	"Exit the Pokedex",
			callback:    	commandExit,
		},
		"help": {
			name:					"help",
			description: 	"Displays a help message",
			callback: 		commandHelp,
		},
	}
	return func() map[string]cliCommand {
		return commandRegistry
	}
}

func commandHelp() error {
	fmt.Println("Welcome to the Pokedex!")
	fmt.Println("Usage:")
	fmt.Println()
	for _, v := range getCommands()() {
		fmt.Printf("%v: %v\n", v.name, v.description)
	}
	return nil
}

func handleCommand(ss []string) {
	command, ok := getCommands()()[ss[0]]
	if !ok {
		fmt.Printf("Unknown command: \"%v\"\n", ss[0])
		return
	}

	err := command.callback()
	if err != nil {
		fmt.Println(fmt.Errorf("%w", err))
	}
}

func main() {
	REPL()
}

func REPL() {
	scanner := bufio.NewScanner(os.Stdin)
	for {
		fmt.Print("Pokedex > ")
		if !scanner.Scan() {
			break
		}
		in := scanner.Text()
		clean := cleanInput(in)
		
		if len(clean) == 0 {
			continue
		}
		
		handleCommand(clean)
	}
}

func cleanInput(text string) []string {
	var ss []string
	lowered_string := strings.ToLower(text)
	for _, s := range strings.Split(lowered_string, " ") {
		s = strings.Trim(s, " \n\t\v\f\r")
		if len(s) != 0 {
			ss = append(ss, s)
		}
	}
	return ss
}
package main

import (
    "fmt"
    "bufio"
    "os"
    "strings"
)

type cliCommand struct {
    name string
    description string
    callback func() error
}

var commandRegistry = map[string]cliCommand{
    "help": {
	name: "help",
	description: "Displays a help message",
	callback: commandHelp,
    },
}

func commandHelp() error {
    fmt.Println("Usage: ")
    for _, v := range commandRegistry {
	fmt.Printf("%v: %v\n", v.name, v.description)
    }
    return nil
}

func handleCommand(ss []string) {
    command, ok := commandRegistry[ss[0]]
    if !ok {
        fmt.Printf("Unknown command: \"%v\"\n", ss[0])
        return
    }

    err := command.callback()
    if err != nil {
        fmt.Println(fmt.Errorf("%w", err))
    }
}

func main() {
    REPL()
}

func REPL() {
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("> ")
        if !scanner.Scan() {
            break
        }
        in := scanner.Text()
        clean := cleanInput(in)
		
        if len(clean) == 0 {
            continue
        }
		
        handleCommand(clean)
    }
}

func cleanInput(text string) []string {
    var ss []string
    lowered_text := strings.ToLower(text)
    for _, s := range strings.Split(lowered_text, " ") {
        s = strings.Trim(s, " \n\t\v\f\r")
        if len(s) != 0 {
            ss = append(ss, s)
        }
    }
    return ss
}

Reply via email to