1
0
mirror of https://github.com/golang/go synced 2024-11-21 15:24:45 -07:00

text/template: allow eq to take more than two arguments

Based on an old suggestion by rsc, it compares the second
and following arguments to the first.

Unfortunately the code cannot be as pretty as rsc's original
because it doesn't require identical types.

R=golang-dev, dsymonds, adg
CC=golang-dev
https://golang.org/cl/13509046
This commit is contained in:
Rob Pike 2013-09-04 13:42:22 +10:00
parent 54b2a83d9a
commit 0ba7ffe289
3 changed files with 54 additions and 35 deletions

View File

@ -326,13 +326,22 @@ functions:
ge
Returns the boolean truth of arg1 >= arg2
These functions work on basic types only (or named basic types,
such as "type Celsius float32"). They implement the Go rules for
comparison of values, except that size and exact type are ignored,
so any integer value may be compared with any other integer value,
any unsigned integer value may be compared with any other unsigned
integer value, and so on. However, as usual, one may not compare
an int with a float32 and so on.
For simpler multi-way equality tests, eq (only) accepts two or more
arguments and compares the second and subsequent to the first,
returning in effect
arg1==arg2 || arg1==arg3 || arg1==arg4 ...
(Unlike with || in Go, however, eq is a function call and all the
arguments will be evaluated.)
The comparison functions work on basic types only (or named basic
types, such as "type Celsius float32"). They implement the Go rules
for comparison of values, except that size and exact type are
ignored, so any integer value may be compared with any other integer
value, any unsigned integer value may be compared with any other
unsigned integer value, and so on. However, as usual, one may not
compare an int with a float32 and so on.
Associated templates

View File

@ -891,6 +891,8 @@ var cmpTests = []cmpTest{
{"eq `xy` `xyz`", "false", true},
{"eq .Xuint .Xuint", "true", true},
{"eq .Xuint .Yuint", "false", true},
{"eq 3 4 5 6 3", "true", true},
{"eq 3 4 5 6 7", "false", true},
{"ne true true", "false", true},
{"ne true false", "true", true},
{"ne 1+2i 1+2i", "false", true},
@ -946,7 +948,6 @@ var cmpTests = []cmpTest{
{"ge .Xuint .Yuint", "false", true},
{"ge .Yuint .Xuint", "true", true},
// Errors
{"eq 3 4 5", "", false}, // Too many arguments.
{"eq `xy` 1", "", false}, // Different types.
{"lt true true", "", false}, // Unordered types.
{"lt 1+0i 1+0i", "", false}, // Unordered types.
@ -970,7 +971,7 @@ func TestComparison(t *testing.T) {
continue
}
if !test.ok && err == nil {
t.Errorf("%s did not error")
t.Errorf("%s did not error", test.expr)
continue
}
if b.String() != test.truth {

View File

@ -264,6 +264,7 @@ func not(arg interface{}) (truth bool) {
var (
errBadComparisonType = errors.New("invalid type for comparison")
errBadComparison = errors.New("incompatible types for comparison")
errNoComparison = errors.New("missing argument for comparison")
)
type kind int
@ -297,39 +298,47 @@ func basicKind(v reflect.Value) (kind, error) {
return invalidKind, errBadComparisonType
}
// eq evaluates the comparison a == b.
func eq(arg1, arg2 interface{}) (bool, error) {
// eq evaluates the comparison a == b || a == c || ...
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
v1 := reflect.ValueOf(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
v2 := reflect.ValueOf(arg2)
k2, err := basicKind(v2)
if err != nil {
return false, err
if len(arg2) == 0 {
return false, errNoComparison
}
if k1 != k2 {
return false, errBadComparison
for _, arg := range arg2 {
v2 := reflect.ValueOf(arg)
k2, err := basicKind(v2)
if err != nil {
return false, err
}
if k1 != k2 {
return false, errBadComparison
}
truth := false
switch k1 {
case boolKind:
truth = v1.Bool() == v2.Bool()
case complexKind:
truth = v1.Complex() == v2.Complex()
case floatKind:
truth = v1.Float() == v2.Float()
case intKind:
truth = v1.Int() == v2.Int()
case stringKind:
truth = v1.String() == v2.String()
case uintKind:
truth = v1.Uint() == v2.Uint()
default:
panic("invalid kind")
}
if truth {
return true, nil
}
}
truth := false
switch k1 {
case boolKind:
truth = v1.Bool() == v2.Bool()
case complexKind:
truth = v1.Complex() == v2.Complex()
case floatKind:
truth = v1.Float() == v2.Float()
case intKind:
truth = v1.Int() == v2.Int()
case stringKind:
truth = v1.String() == v2.String()
case uintKind:
truth = v1.Uint() == v2.Uint()
default:
panic("invalid kind")
}
return truth, nil
return false, nil
}
// ne evaluates the comparison a != b.