瀏覽代碼

Improve slice reply helper functions (#289)

- Add Int64s, fixes #246
- Add Float64s, fixes #288
- Move common code for slice functions to a function.
Gary Burd 8 年之前
父節點
當前提交
200b674d74
共有 2 個文件被更改,包括 87 次插入55 次删除
  1. 69 47
      redis/reply.go
  2. 18 8
      redis/reply_test.go

+ 69 - 47
redis/reply.go

@@ -243,34 +243,59 @@ func Values(reply interface{}, err error) ([]interface{}, error) {
 	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
 	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
 }
 }
 
 
-// Strings is a helper that converts an array command reply to a []string. If
-// err is not equal to nil, then Strings returns nil, err. Nil array items are
-// converted to "" in the output slice. Strings returns an error if an array
-// item is not a bulk string or nil.
-func Strings(reply interface{}, err error) ([]string, error) {
+func sliceHelper(reply interface{}, err error, name string, makeSlice func(int), assign func(int, []byte) error) error {
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return err
 	}
 	}
 	switch reply := reply.(type) {
 	switch reply := reply.(type) {
 	case []interface{}:
 	case []interface{}:
-		result := make([]string, len(reply))
+		makeSlice(len(reply))
 		for i := range reply {
 		for i := range reply {
 			if reply[i] == nil {
 			if reply[i] == nil {
 				continue
 				continue
 			}
 			}
 			p, ok := reply[i].([]byte)
 			p, ok := reply[i].([]byte)
 			if !ok {
 			if !ok {
-				return nil, fmt.Errorf("redigo: unexpected element type for Strings, got type %T", reply[i])
+				return fmt.Errorf("redigo: unexpected element type for %s, got type %T", name, reply[i])
+			}
+			if err := assign(i, p); err != nil {
+				return err
 			}
 			}
-			result[i] = string(p)
 		}
 		}
-		return result, nil
+		return nil
 	case nil:
 	case nil:
-		return nil, ErrNil
+		return ErrNil
 	case Error:
 	case Error:
-		return nil, reply
+		return reply
 	}
 	}
-	return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply)
+	return fmt.Errorf("redigo: unexpected type for %s, got type %T", name, reply)
+}
+
+// Float64s is a helper that converts an array command reply to a []float64. If
+// err is not equal to nil, then Float64s returns nil, err. Nil array items are
+// converted to 0 in the output slice. Floats64 returns an error if an array
+// item is not a bulk string or nil.
+func Float64s(reply interface{}, err error) ([]float64, error) {
+	var result []float64
+	err = sliceHelper(reply, err, "Float64s", func(n int) { result = make([]float64, n) }, func(i int, p []byte) error {
+		f, err := strconv.ParseFloat(string(p), 64)
+		result[i] = f
+		return err
+	})
+	return result, err
+}
+
+// Strings is a helper that converts an array command reply to a []string. If
+// err is not equal to nil, then Strings returns nil, err. Nil array items are
+// converted to "" in the output slice. Strings returns an error if an array
+// item is not a bulk string or nil.
+func Strings(reply interface{}, err error) ([]string, error) {
+	var result []string
+	err = sliceHelper(reply, err, "Strings", func(n int) { result = make([]string, n) }, func(i int, p []byte) error {
+		result[i] = string(p)
+		return nil
+	})
+	return result, err
 }
 }
 
 
 // ByteSlices is a helper that converts an array command reply to a [][]byte.
 // ByteSlices is a helper that converts an array command reply to a [][]byte.
@@ -278,43 +303,40 @@ func Strings(reply interface{}, err error) ([]string, error) {
 // items are stay nil. ByteSlices returns an error if an array item is not a
 // items are stay nil. ByteSlices returns an error if an array item is not a
 // bulk string or nil.
 // bulk string or nil.
 func ByteSlices(reply interface{}, err error) ([][]byte, error) {
 func ByteSlices(reply interface{}, err error) ([][]byte, error) {
-	if err != nil {
-		return nil, err
-	}
-	switch reply := reply.(type) {
-	case []interface{}:
-		result := make([][]byte, len(reply))
-		for i := range reply {
-			if reply[i] == nil {
-				continue
-			}
-			p, ok := reply[i].([]byte)
-			if !ok {
-				return nil, fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", reply[i])
-			}
-			result[i] = p
-		}
-		return result, nil
-	case nil:
-		return nil, ErrNil
-	case Error:
-		return nil, reply
-	}
-	return nil, fmt.Errorf("redigo: unexpected type for ByteSlices, got type %T", reply)
+	var result [][]byte
+	err = sliceHelper(reply, err, "ByteSlices", func(n int) { result = make([][]byte, n) }, func(i int, p []byte) error {
+		result[i] = p
+		return nil
+	})
+	return result, err
 }
 }
 
 
-// Ints is a helper that converts an array command reply to a []int. If
-// err is not equal to nil, then Ints returns nil, err.
+// Int64s is a helper that converts an array command reply to a []int64.
+// If err is not equal to nil, then Int64s returns nil, err. Nil array
+// items are stay nil. Int64s returns an error if an array item is not a
+// bulk string or nil.
+func Int64s(reply interface{}, err error) ([]int64, error) {
+	var result []int64
+	err = sliceHelper(reply, err, "Int64s", func(n int) { result = make([]int64, n) }, func(i int, p []byte) error {
+		n, err := strconv.ParseInt(string(p), 10, 64)
+		result[i] = n
+		return err
+	})
+	return result, err
+}
+
+// Ints is a helper that converts an array command reply to a []in.
+// If err is not equal to nil, then Ints returns nil, err. Nil array
+// items are stay nil. Ints returns an error if an array item is not a
+// bulk string or nil.
 func Ints(reply interface{}, err error) ([]int, error) {
 func Ints(reply interface{}, err error) ([]int, error) {
-	var ints []int
-	values, err := Values(reply, err)
-	if err != nil {
-		return ints, err
-	}
-	if err := ScanSlice(values, &ints); err != nil {
-		return ints, err
-	}
-	return ints, nil
+	var result []int
+	err = sliceHelper(reply, err, "Ints", func(n int) { result = make([]int, n) }, func(i int, p []byte) error {
+		n, err := strconv.Atoi(string(p))
+		result[i] = n
+		return err
+	})
+	return result, err
 }
 }
 
 
 // StringMap is a helper that converts an array of strings (alternating key, value)
 // StringMap is a helper that converts an array of strings (alternating key, value)

+ 18 - 8
redis/reply_test.go

@@ -41,30 +41,40 @@ var replyTests = []struct {
 		ve(redis.Ints([]interface{}{[]byte("4"), []byte("5")}, nil)),
 		ve(redis.Ints([]interface{}{[]byte("4"), []byte("5")}, nil)),
 		ve([]int{4, 5}, nil),
 		ve([]int{4, 5}, nil),
 	},
 	},
+	{
+		"ints([v1, nil, v2])",
+		ve(redis.Ints([]interface{}{[]byte("4"), nil, []byte("5")}, nil)),
+		ve([]int{4, 0, 5}, nil),
+	},
+	{
+		"ints([v1, nil, v2])",
+		ve(redis.Ints([]interface{}{[]byte("4"), nil, []byte("5")}, nil)),
+		ve([]int{4, 0, 5}, nil),
+	},
 	{
 	{
 		"ints(nil)",
 		"ints(nil)",
 		ve(redis.Ints(nil, nil)),
 		ve(redis.Ints(nil, nil)),
 		ve([]int(nil), redis.ErrNil),
 		ve([]int(nil), redis.ErrNil),
 	},
 	},
+	{
+		"int64s([v1, v2])",
+		ve(redis.Int64s([]interface{}{[]byte("4"), []byte("5")}, nil)),
+		ve([]int64{4, 5}, nil),
+	},
 	{
 	{
 		"strings([v1, v2])",
 		"strings([v1, v2])",
 		ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
 		ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
 		ve([]string{"v1", "v2"}, nil),
 		ve([]string{"v1", "v2"}, nil),
 	},
 	},
-	{
-		"strings(nil)",
-		ve(redis.Strings(nil, nil)),
-		ve([]string(nil), redis.ErrNil),
-	},
 	{
 	{
 		"byteslices([v1, v2])",
 		"byteslices([v1, v2])",
 		ve(redis.ByteSlices([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
 		ve(redis.ByteSlices([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
 		ve([][]byte{[]byte("v1"), []byte("v2")}, nil),
 		ve([][]byte{[]byte("v1"), []byte("v2")}, nil),
 	},
 	},
 	{
 	{
-		"byteslices(nil)",
-		ve(redis.ByteSlices(nil, nil)),
-		ve([][]byte(nil), redis.ErrNil),
+		"float64s([v1, v2])",
+		ve(redis.Float64s([]interface{}{[]byte("1.234"), []byte("5.678")}, nil)),
+		ve([]float64{1.234, 5.678}, nil),
 	},
 	},
 	{
 	{
 		"values([v1, v2])",
 		"values([v1, v2])",