我遇到以下问题: 我的golang程序将一些信息转换为JSON。 例如,它导致以下json:
{
"value":40,
"unit":"some_string"
}
问题是值的“输入”为40.0,编组剥离了结尾的零。如果读取JSON的EPL能够将浮点数读取为40而没有.0
,那将是没有问题的因此JSON输出应类似于:
{
"value":40.0,
"unit":"some_string"
}
是否可以“阻止” json.Marshal()删除零?
编辑:值必须是浮点数
答案 0 :(得分:3)
默认情况下,如果浮点数的值为整数,则不带小数点和小数。表示较短,表示相同的数字。
如果要控制数字在JSON表示中的显示方式,请使用json.Number
类型。
示例:
type Pt struct {
Value json.Number
Unit string
}
func main() {
data, err := json.Marshal(Pt{json.Number("40.0"), "some_string"})
fmt.Println(string(data), err)
}
输出(在Go Playground上尝试):
{"Value":40.0,"Unit":"some_string"} <nil>
如果您将数字作为float64
值,则可以将其转换为json.Number
,如下所示:
func toNumber(f float64) json.Number {
var s string
if f == float64(int64(f)) {
s = fmt.Sprintf("%.1f", f) // 1 decimal if integer
} else {
s = fmt.Sprint(f)
}
return json.Number(s)
}
测试:
f := 40.0
data, err := json.Marshal(Pt{toNumber(f), "some_string"})
fmt.Println(string(data), err)
f = 40.123
data, err = json.Marshal(Pt{toNumber(f), "some_string"})
fmt.Println(string(data), err)
输出(在Go Playground上尝试):
{"Value":40.0,"Unit":"some_string"} <nil>
{"Value":40.123,"Unit":"some_string"} <nil>
另一个方向,如果您想要float64
的{{1}}值,只需调用其Number.Float64()
方法。
答案 1 :(得分:1)
@icza提供了一个很好的答案,但只是提供了另一个选择,您可以定义自己的浮点类型并为其定义序列化。像这样
type KeepZero float64
func (f KeepZero) MarshalJSON() ([]byte, error) {
if float64(f) == float64(int(f)) {
return []byte(strconv.FormatFloat(float64(f), 'f', 1, 32)), nil
}
return []byte(strconv.FormatFloat(float64(f), 'f', -1, 32)), nil
}
type Pt struct {
Value KeepZero
Unit string
}
func main() {
data, err := json.Marshal(Pt{40.0, "some_string"})
fmt.Println(string(data), err)
}
结果为{"Value":40.0,"Unit":"some_string"} <nil>
。 Check it out in playground.
答案 2 :(得分:0)
将值另存为字符串,并在需要时将其强制返回。
答案 3 :(得分:0)
我遇到类似的问题,我想将浮点值为f {x map[string]interface{}
的{{1}}编组为JSON,1.0
。我通过为自定义浮动类型添加自定义Marshal函数,然后将地图中的浮动替换为自定义类型来解决了此问题:
1.0
然后替换所有float64节点:
type customFloat float64
func (f customFloat) MarshalJSON() ([]byte, error) {
if float64(f) == math.Trunc(float64(f)) {
return []byte(fmt.Sprintf("%.1f", f)), nil
}
return json.Marshal(float64(f))
}
func replaceFloat(value map[string]interface{}) {
for k, v := range value {
switch val := v.(type) {
case map[string]interface{}:
replaceFloat(val)
case float64:
value[k] = customFloat(val)
}
}
}
这将打印出replaceFloat(myValue)
bytes, err := json.Marshal(myValue)
之类的浮点数
答案 4 :(得分:0)
import datetime
# I started by creating lists for the months, their days, and the days of the week.
month_list = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
days_of_week = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
def calendar(month, year):
'''
(int, int) -> None
Prints a calendar for
given month and year.
CALLS: is_leap(year)
CALLED BY: main()
'''
# I first wanted to check if the year is a leap year, and if so, modify the days in feb
if is_leap(year):
days_in_month[1] = 29
# Now i set variables to values within my lists based of input data for year and month
month_corrected = month_list[month-1]
num_days = days_in_month[month-1]
# Now I figure out what my start date is for the given month of the year
day_one = datetime.date(year, month, 1)
start_day = day_one.isoweekday()
# Begin by printing the month and year
print(month_corrected[:3], year)
# Print the days of the week for my calendar
print(' '.join(['{0:<2}'.format(w) for w in days_of_week]))
# Print a blank space on the days before my start day variable
print('{0:>3}'.format('')*start_day, end='')
# if my start day begins on sunday, start a new line and set my start day to zero
if start_day >= 7:
print()
start_day = 0
# Begin looping through the number of days in the month starting with my start day
for day in range(1, num_days+1):
# Print each day
print('{0:>2}'.format(day), end=' ')
# up my start day variable each time to act as a counter
start_day += 1
if start_day >= 7:
# If my start day variable is on Sunday, start new line
print()
# Reset my day counter
start_day = 0
print()
def is_leap(year):
'''
(int) -> bool
Checks if year is a leap year
credit to Steven Summers
CALLS:
CALLED BY: calendar()
>>> is_leap(2000)
True
>>> is_leap(1900)
False
'''
if year % 4 == 0:
if year % 100 == 0:
if year % 400 == 0:
return True
else:
return False
else:
return True
else:
return False
def main():
'''
() -> None
Drives calendar program
CALLS: calendar(month, year)
CALLED BY:
'''
make_calendars = True
while make_calendars:
# create input loops for year and month to run calendar function
good_year = False
while good_year == False:
input_year = input('Enter year (blank to exit): ')
# some code to ensure input is within datetime parameters
if input_year == '':
make_calendars = False
return None
else:
year = int(input_year)
if 1 > year > 9999:
print("Must enter an integer between 1 and 9999")
else:
good_year = True
good_month = False
while good_month == False:
# a blank entry will print the entire year
input_month = input('Enter month (blank to print entire year: ')
# some code to ensure input is within datetime parameters
if input_month == '':
for i in range(1,13):
calendar(i, year)
main()
else:
if input_month[0] == '0':
input_month = input_month[1:]
month = int(input_month)
if 1 > month > 12:
print("Must enter an integer between 1 and 12")
else:
good_month = True
if good_year == True and good_month == True:
calendar(month, year)
if __name__ == '__main__':
main()
这样使用
type MyFloat float64
func (mf MyFloat) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%.1f", float64(mf))), nil
}
以您需要的精度替换 type PricePoint struct {
Price MyFloat `json:"price"`
From time.Time `json:"valid_from"`
To time.Time `json:"valid_to"`
}
中的1