为什么 Go 将 Postgresql 数字和小数列视为 []uint8?
Why does Go treat a Postgresql numeric & decimal columns as []uint8?
我不确定这是 Go 中的错误还是我不明白。我有以下内容:
package main
import (
"database/sql"
"log"
"reflect"
_ "github.com/lib/pq"
)
func main() {
Db, err := sql.Open("postgres", "user=yoitsme password=openupitsme host=x.x.x.x dbname=mydb")
if err != nil {
log.Println(err)
}
rows, err := Db.Query("SELECT 1.3250::numeric, 8.548::decimal, 908.234::float, 1234::integer")
defer rows.Close()
for rows.Next() {
var col1, col2, col3, col4 interface{}
if err := rows.Scan(&col1, &col2, &col3, &col4); err != nil {
log.Println(err)
}
log.Println(col1, reflect.TypeOf(col1))
log.Println(col2, reflect.TypeOf(col2))
log.Println(col3, reflect.TypeOf(col3))
log.Println(col4, reflect.TypeOf(col4))
}
if err = rows.Err(); err != nil {
log.Println(err)
}
}
这会打印:
2015/08/11 09:35:47 [49 46 51 50 53 48] []uint8
2015/08/11 09:35:47 [56 46 53 52 56] []uint8
2015/08/11 09:35:47 908.234 float64
2015/08/11 09:35:47 1234 int64
因此,对于实际上是数字的前两列,我得到 []uint8(例如字符串)。最后 2 列符合预期。根据 Postgresql Numeric & Decimal types are part of the SQL standard。那么,为什么 Go 在他们的 database/sql 包中不遵循 SQL 标准呢?是因为 Go 没有内置 "Decimal" 类型吗?由于语言的缺陷,database/sql 包将数字转换为字符串似乎是错误的....
因为没有更好的解决办法。 (至少在 Go 1.5's big.Float
之前是这样)。还有哪些其他选择?
把它变成一个整数。显然这是一个糟糕的解决方案,因为数字可以有小数部分。
把它变成float64
。这是邪恶。特别是如果你正在处理金钱(numeric
和 decimal
这样的类型使用最多)。
这个特定的数据库驱动程序选择 return 包含数字的字符串 - 让 你 决定是否失去一些精度(通过将其转换为 float64
与 strconv
) 或使用 decimal/precise 数字库(如 gmp
或 math/big
)。
这是开发人员对问题的回答问题:https://github.com/lib/pq/issues/648
It's not safe to use a float64 type for a decimal because floats can't represent all decimals. For example, decimals support exponents much larger than floats, and the coefficients of floats, when converted to their base-2 representation, will change. It is trivial in go to convert a string to a float, so we are going to keep this behavior.
我不确定这是 Go 中的错误还是我不明白。我有以下内容:
package main
import (
"database/sql"
"log"
"reflect"
_ "github.com/lib/pq"
)
func main() {
Db, err := sql.Open("postgres", "user=yoitsme password=openupitsme host=x.x.x.x dbname=mydb")
if err != nil {
log.Println(err)
}
rows, err := Db.Query("SELECT 1.3250::numeric, 8.548::decimal, 908.234::float, 1234::integer")
defer rows.Close()
for rows.Next() {
var col1, col2, col3, col4 interface{}
if err := rows.Scan(&col1, &col2, &col3, &col4); err != nil {
log.Println(err)
}
log.Println(col1, reflect.TypeOf(col1))
log.Println(col2, reflect.TypeOf(col2))
log.Println(col3, reflect.TypeOf(col3))
log.Println(col4, reflect.TypeOf(col4))
}
if err = rows.Err(); err != nil {
log.Println(err)
}
}
这会打印:
2015/08/11 09:35:47 [49 46 51 50 53 48] []uint8
2015/08/11 09:35:47 [56 46 53 52 56] []uint8
2015/08/11 09:35:47 908.234 float64
2015/08/11 09:35:47 1234 int64
因此,对于实际上是数字的前两列,我得到 []uint8(例如字符串)。最后 2 列符合预期。根据 Postgresql Numeric & Decimal types are part of the SQL standard。那么,为什么 Go 在他们的 database/sql 包中不遵循 SQL 标准呢?是因为 Go 没有内置 "Decimal" 类型吗?由于语言的缺陷,database/sql 包将数字转换为字符串似乎是错误的....
因为没有更好的解决办法。 (至少在 Go 1.5's big.Float
之前是这样)。还有哪些其他选择?
把它变成一个整数。显然这是一个糟糕的解决方案,因为数字可以有小数部分。
把它变成
float64
。这是邪恶。特别是如果你正在处理金钱(numeric
和decimal
这样的类型使用最多)。
这个特定的数据库驱动程序选择 return 包含数字的字符串 - 让 你 决定是否失去一些精度(通过将其转换为 float64
与 strconv
) 或使用 decimal/precise 数字库(如 gmp
或 math/big
)。
这是开发人员对问题的回答问题:https://github.com/lib/pq/issues/648
It's not safe to use a float64 type for a decimal because floats can't represent all decimals. For example, decimals support exponents much larger than floats, and the coefficients of floats, when converted to their base-2 representation, will change. It is trivial in go to convert a string to a float, so we are going to keep this behavior.