我有一个验证功能积极,它的作品,但看起来很丑.
type Positiver interface {
decimal.Decimal | int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64
}
//nolint:cyclop
func Positive[T Positiver](value T, name string, errs *[]error) {
addError := func() {
err := fmt.Errorf(`%s %w, but it's %v`, name, failures.ShouldBePositive, value)
*errs = append(*errs, err)
}
const prescision = 8
switch val := any(value).(type) {
case decimal.Decimal:
if val.IsNegative() || val.IsZero() {
err := fmt.Errorf(`%s %w, but it's %s`, name, failures.ShouldBePositive, val.StringFixedBank(prescision))
*errs = append(*errs, err)
}
return
case int:
if val <= 0 {
addError()
}
case int64:
if val <= 0 {
addError()
}
case int32:
if val <= 0 {
addError()
}
case int16:
if val <= 0 {
addError()
}
case int8:
if val <= 0 {
addError()
}
case uint:
if val <= 0 {
addError()
}
case uint64:
if val <= 0 {
addError()
}
case uint32:
if val <= 0 {
addError()
}
case uint16:
if val <= 0 {
addError()
}
case uint8:
if val <= 0 {
addError()
}
case float32:
if val <= 0 {
addError()
}
case float64:
if val <= 0 {
addError()
}
default:
panic(fmt.Sprintf(`%T is not supported type`, val))
}
}
我知道使用[]error是一种不好的方法,最好是返回一个 Package 的错误。但这是一个兼容性问题。
我试着这样做:
func Positive[T Positiver](value T, name string, errs *[]error) {
switch val := any(value).(type) {
case decimal.Decimal:
if val.IsNegative() || val.IsZero() {
err := fmt.Errorf(`%s %w, but it's not`, name, failures.ShouldBePositive)
*errs = append(*errs, err)
}
return
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
if val.(int64) <= 0 {
err := fmt.Errorf(`%s %w, but it's not`, name, failures.ShouldBePositive)
*errs = append(*errs, err)
}
return
case float32, float64:
if val.(float64) < 0 {
err := fmt.Errorf(`%s %w, but it's not`, name, failures.ShouldBePositive)
*errs = append(*errs, err)
}
return
default:
panic(fmt.Sprintf(`%T is not supported type`, val))
}
}
但是这种方法返回了一个错误:测试死机:接口转换:interface {}是int,不是int 64
比较该值是否超过零的更好方法是什么?
1条答案
按热度按时间3pmvbmvn1#
您的代码不适用于“接口转换:interface {}是int,而不是int 64”,因为在多类型
case
中,类型开关变量val
保持其原始类型。另请参阅:golang multiple case in type switch详细信息。所以在这种情况下,为了使用顺序运算符,你确实必须Assert某个东西。那个“东西”**可能是一个类型参数。
但是这段代码仍然不能使用order运算符,因为约束
Positive
包含decimal.Decimal
,它不支持排序。尝试为
decimal.Decimal
写一个case
,为其他数值类型写一个case
也不会很好,因为你没有一个好的方法来减少类型约束的类型集。你正在为每个类型写一个case
。有一天Go可能允许在类型开关中使用联合约束。你现在可以做的是静态地处理
decimal.Decimal
和其他数值类型。你可以使用constraints
包中的类型来避免重新声明所有内容:Signed
,Unsigned
和Float
。那么一个只有数值类型的朴素函数就像这样简单:但是对于浮点数,使用
<
是不够的。浮点数变量也可以是NaN或+/-infinity。你必须决定如何排序NaN;无穷大有符号位,但在我看来,最好使用math.IsInf
,这样就不会在顺序运算符后面隐藏东西。所以总而言之,我认为这个函数使用反射会更好,反射可能会更慢,但代码并不完全糟糕。下面是你的示例的简化版本: