Great! If I had checked this thread when you posted this I (probably) could have saved myself 3 hours of work.
I got it working with a two-pass scheme using text/template and some channels. Here is what I came up with: package main import ( "text/template" "bytes" "context" "fmt" "github.com/google/uuid" "time" ) type resultpair struct { key string value string } func getFuncMap(ctx context.Context, resultsQueue chan resultpair) (*int, template.FuncMap) { totalJobs := 0 var funcMap = template.FuncMap{ "sleep": func() string { totalJobs = totalJobs + 1 token := uuid.New() go func() { time.Sleep(1 * time.Second) resultsQueue <- resultpair{token.String(), "REAL_VALUE!"} }() return "{{ getOutput \"" + token.String() + "\" }}" }, } return &totalJobs, funcMap } func getFuncMapNested(ctx context.Context, output map[string]string) template.FuncMap { var funcMapNested = template.FuncMap{ "getOutput": func(input string) string { return output[input] }, } return funcMapNested } func main() { initial := "{{sleep}} {{sleep}} {{sleep}}" resultsQueue := make(chan resultpair) outputQueue := make(chan map[string]string) // totalJobs is decieving: only ever accessed by one thread at a time, so shouldn't need locking (I think) totalJobs, funcMap := getFuncMap(context.TODO(), resultsQueue) fmt.Printf("About to execute first template: %s\n", initial) fmt.Printf("TOTAL JOBS: %d\n", *totalJobs) tmpl, _ := template.New("test").Funcs(funcMap).Parse(initial) var buf bytes.Buffer tmpl.Execute(&buf, nil) fmt.Printf("Got translated template: %s\n", buf.String()) fmt.Printf("TOTAL JOBS: %d\n", *totalJobs) go func(totalJobs *int) { var results map[string]string results = make(map[string]string) for i := 0; i < *totalJobs; i++ { res := <-resultsQueue results[res.key] = res.value } outputQueue <- results close(outputQueue) }(totalJobs) output := <-outputQueue close(resultsQueue) fmt.Printf("Output of the goroutine: %s\n", output) funcMapNested := getFuncMapNested(context.TODO(), output) tmpl2, _ := template.New("nested").Funcs(funcMapNested).Parse(buf.String()) var buf2 bytes.Buffer tmpl2.Execute(&buf2, nil) fmt.Printf("results: %s\n", buf2.String()) } OUTPUT: $ time go run ./commands/try.go About to execute first template: {{sleep}} {{sleep}} {{sleep}} TOTAL JOBS: 0 Got translated template: {{ getOutput "bc7dcfa0-89d9-45e9-bd40-eb2db6f51db0" }} {{ getOutput "f2539f15-378b-408d-8c6e-d3822e985a6b" }} {{ getOutput "56c9d239-d08d-43e8-80de-dd97ef157b6a" }} TOTAL JOBS: 3 Output of the goroutine: map[bc7dcfa0-89d9-45e9-bd40-eb2db6f51db0:REAL_VALUE! f2539f15-378b-408d-8c6e-d3822e985a6b:REAL_VALUE! 56c9d239-d08d-43e8-80de-dd97ef157b6a:REAL_VALUE!] results: REAL_VALUE! REAL_VALUE! REAL_VALUE! real 0m1.319s user 0m0.278s sys 0m0.098s On Wednesday, May 31, 2017 at 9:09:51 PM UTC-5, robfig wrote: > > We do this exact thing except using closure templates > https://blog.gopheracademy.com/advent-2014/soy-programmable-templates/ > -- 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. For more options, visit https://groups.google.com/d/optout.