github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/vals/string.go (about) 1 package vals 2 3 import ( 4 "math" 5 "strconv" 6 "strings" 7 ) 8 9 // Stringer wraps the String method. 10 type Stringer interface { 11 // Stringer converts the receiver to a string. 12 String() string 13 } 14 15 // ToString converts a Value to string. It is implemented for the builtin 16 // float64 and string types, and type satisfying the Stringer interface. It 17 // falls back to Repr(v, NoPretty). 18 func ToString(v interface{}) string { 19 switch v := v.(type) { 20 case int: 21 return strconv.Itoa(v) 22 case float64: 23 return formatFloat64(v) 24 case string: 25 return v 26 case Stringer: 27 return v.String() 28 default: 29 return Repr(v, NoPretty) 30 } 31 } 32 33 func formatFloat64(f float64) string { 34 // Go's 'g' format is not quite ideal for printing floating point numbers; 35 // it uses scientific notation too aggressively, and relatively small 36 // numbers like 1234567 are printed with scientific notations, something we 37 // don't really want. 38 // 39 // So we use a different algorithm for determining when to use scientific 40 // notation. The algorithm is reverse-engineered from Racket's; it may not 41 // be a perfect clone but hopefully good enough. 42 // 43 // See also b.elv.sh/811 for more context. 44 s := strconv.FormatFloat(f, 'f', -1, 64) 45 noPoint := !strings.ContainsRune(s, '.') 46 if (noPoint && len(s) > 14 && s[len(s)-1] == '0') || 47 strings.HasPrefix(s, "0.0000") { 48 return strconv.FormatFloat(f, 'e', -1, 64) 49 } else if noPoint && !math.IsNaN(f) && !math.IsInf(f, 0) { 50 return s + ".0" 51 } 52 return s 53 }