github.com/elves/elvish@v0.15.0/pkg/eval/vals/string.go (about)

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