1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:57:58 -07:00

text/template: support range-over-int

Fixes #66107

Change-Id: I19b466e3fb17557cf4f198b7fd8c13e774d854b1
Reviewed-on: https://go-review.googlesource.com/c/go/+/615095
Auto-Submit: Ian Lance Taylor <iant@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Commit-Queue: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
qiulaidongfeng 2024-09-25 20:20:06 +08:00 committed by Gopher Robot
parent b7e4d2067c
commit 712d47ce15
4 changed files with 43 additions and 3 deletions

View File

@ -1 +1 @@
Templates now support range-over-func.
Templates now support range-over-func and range-over-int.

View File

@ -99,7 +99,7 @@ data, defined in detail in the corresponding sections that follow.
{{range pipeline}} T1 {{end}}
The value of the pipeline must be an array, slice, map, iter.Seq,
iter.Seq2 or channel.
iter.Seq2, integer or channel.
If the value of the pipeline has length zero, nothing is output;
otherwise, dot is set to the successive elements of the array,
slice, or map and T1 is executed. If the value is a map and the
@ -108,7 +108,7 @@ data, defined in detail in the corresponding sections that follow.
{{range pipeline}} T1 {{else}} T0 {{end}}
The value of the pipeline must be an array, slice, map, iter.Seq,
iter.Seq2 or channel.
iter.Seq2, integer or channel.
If the value of the pipeline has length zero, dot is unaffected and
T0 is executed; otherwise, dot is set to the successive elements
of the array, slice, or map and T1 is executed.

View File

@ -395,6 +395,22 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
s.walk(elem, r.List)
}
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if len(r.Pipe.Decl) > 1 {
s.errorf("can't use %s to iterate over more than one variable", val)
break
}
run := false
for v := range val.Seq() {
run = true
// Pass element as second value, as we do for channels.
oneIteration(reflect.Value{}, v)
}
if !run {
break
}
return
case reflect.Array, reflect.Slice:
if val.Len() == 0 {
break

View File

@ -613,6 +613,19 @@ var execTests = []execTest{
{"i,x range iter.Seq[int]", `{{$i := 0}}{{$x := 0}}{{range $i = .}}{{$i}}{{end}}`, "01", fVal1(2), true},
{"range iter.Seq[int] else", `{{range $i := .}}{{$i}}{{else}}empty{{end}}`, "empty", fVal1(0), true},
{"range iter.Seq2[int,int] else", `{{range $i := .}}{{$i}}{{else}}empty{{end}}`, "empty", fVal2(0), true},
{"range int8", rangeTestInt, rangeTestData[int8](), int8(5), true},
{"range int16", rangeTestInt, rangeTestData[int16](), int16(5), true},
{"range int32", rangeTestInt, rangeTestData[int32](), int32(5), true},
{"range int64", rangeTestInt, rangeTestData[int64](), int64(5), true},
{"range int", rangeTestInt, rangeTestData[int](), int(5), true},
{"range uint8", rangeTestInt, rangeTestData[uint8](), uint8(5), true},
{"range uint16", rangeTestInt, rangeTestData[uint16](), uint16(5), true},
{"range uint32", rangeTestInt, rangeTestData[uint32](), uint32(5), true},
{"range uint64", rangeTestInt, rangeTestData[uint64](), uint64(5), true},
{"range uint", rangeTestInt, rangeTestData[uint](), uint(5), true},
{"range uintptr", rangeTestInt, rangeTestData[uintptr](), uintptr(5), true},
{"range uintptr(0)", `{{range $v := .}}{{print $v}}{{else}}empty{{end}}`, "empty", uintptr(0), true},
{"range 5", `{{range $v := 5}}{{printf "%T%d" $v $v}}{{end}}`, rangeTestData[int](), nil, true},
// Cute examples.
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
@ -737,6 +750,17 @@ func fVal2(i int) iter.Seq2[int, int] {
}
}
const rangeTestInt = `{{range $v := .}}{{printf "%T%d" $v $v}}{{end}}`
func rangeTestData[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr]() string {
I := T(5)
var buf strings.Builder
for i := T(0); i < I; i++ {
fmt.Fprintf(&buf, "%T%d", i, i)
}
return buf.String()
}
func zeroArgs() string {
return "zeroArgs"
}