// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package strconvimport// lower(c) is a lower-case letter if and only if// c is either that lower-case letter or the equivalent upper-case letter.// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'.// Note that lower of non-letters can produce other non-letters.func ( byte) byte {return | ('x' - 'X')}// ErrRange indicates that a value is out of range for the target type.varErrRange = errors.New("value out of range")// ErrSyntax indicates that a value does not have the right syntax for the target type.varErrSyntax = errors.New("invalid syntax")// A NumError records a failed conversion.typeNumErrorstruct {Funcstring// the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)Numstring// the inputErrerror// the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)}func ( *NumError) () string {return"strconv." + .Func + ": " + "parsing " + Quote(.Num) + ": " + .Err.Error()}func ( *NumError) () error { return .Err }// cloneString returns a string copy of x.//// All ParseXXX functions allow the input string to escape to the error value.// This hurts strconv.ParseXXX(string(b)) calls where b is []byte since// the conversion from []byte must allocate a string on the heap.// If we assume errors are infrequent, then we can avoid escaping the input// back to the output by copying it first. This allows the compiler to call// strconv.ParseXXX without a heap allocation for most []byte to string// conversions, since it can now prove that the string cannot escape Parse.//// TODO: Use strings.Clone instead? However, we cannot depend on "strings"// since it incurs a transitive dependency on "unicode".// Either move strings.Clone to an internal/bytealg or make the// "strings" to "unicode" dependency lighter (see https://go.dev/issue/54098).func ( string) string { returnstring([]byte()) }func (, string) *NumError {return &NumError{, cloneString(), ErrSyntax}}func (, string) *NumError {return &NumError{, cloneString(), ErrRange}}func (, string, int) *NumError {return &NumError{, cloneString(), errors.New("invalid base " + Itoa())}}func (, string, int) *NumError {return &NumError{, cloneString(), errors.New("invalid bit size " + Itoa())}}constintSize = 32 << (^uint(0) >> 63)// IntSize is the size in bits of an int or uint value.constIntSize = intSizeconstmaxUint64 = 1<<64 - 1// ParseUint is like ParseInt but for unsigned numbers.//// A sign prefix is not permitted.func ( string, int, int) (uint64, error) {const = "ParseUint"if == "" {return0, syntaxError(, ) } := == 0 := switch {case2 <= && <= 36:// valid base; nothing to docase == 0:// Look for octal, hex prefix. = 10if [0] == '0' {switch {caselen() >= 3 && lower([1]) == 'b': = 2 = [2:]caselen() >= 3 && lower([1]) == 'o': = 8 = [2:]caselen() >= 3 && lower([1]) == 'x': = 16 = [2:]default: = 8 = [1:] } }default:return0, baseError(, , ) }if == 0 { = IntSize } elseif < 0 || > 64 {return0, bitSizeError(, , ) }// Cutoff is the smallest number such that cutoff*base > maxUint64. // Use compile-time constants for common cases.varuint64switch {case10: = maxUint64/10 + 1case16: = maxUint64/16 + 1default: = maxUint64/uint64() + 1 } := uint64(1)<<uint() - 1 := falsevaruint64for , := range []byte() {varbyteswitch {case == '_' && : = truecontinuecase'0' <= && <= '9': = - '0'case'a' <= lower() && lower() <= 'z': = lower() - 'a' + 10default:return0, syntaxError(, ) }if >= byte() {return0, syntaxError(, ) }if >= {// n*base overflowsreturn , rangeError(, ) } *= uint64() := + uint64()if < || > {// n+d overflowsreturn , rangeError(, ) } = }if && !underscoreOK() {return0, syntaxError(, ) }return , nil}// ParseInt interprets a string s in the given base (0, 2 to 36) and// bit size (0 to 64) and returns the corresponding value i.//// The string may begin with a leading sign: "+" or "-".//// If the base argument is 0, the true base is implied by the string's// prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o",// 16 for "0x", and 10 otherwise. Also, for argument base 0 only,// underscore characters are permitted as defined by the Go syntax for// [integer literals].//// The bitSize argument specifies the integer type// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64// correspond to int, int8, int16, int32, and int64.// If bitSize is below 0 or above 64, an error is returned.//// The errors that ParseInt returns have concrete type *NumError// and include err.Num = s. If s is empty or contains invalid// digits, err.Err = ErrSyntax and the returned value is 0;// if the value corresponding to s cannot be represented by a// signed integer of the given size, err.Err = ErrRange and the// returned value is the maximum magnitude integer of the// appropriate bitSize and sign.//// [integer literals]: https://go.dev/ref/spec#Integer_literalsfunc ( string, int, int) ( int64, error) {const = "ParseInt"if == "" {return0, syntaxError(, ) }// Pick off leading sign. := := falseif [0] == '+' { = [1:] } elseif [0] == '-' { = true = [1:] }// Convert unsigned and check range.varuint64 , = ParseUint(, , )if != nil && .(*NumError).Err != ErrRange { .(*NumError).Func = .(*NumError).Num = cloneString()return0, }if == 0 { = IntSize } := uint64(1 << uint(-1))if ! && >= {returnint64( - 1), rangeError(, ) }if && > {return -int64(), rangeError(, ) } := int64()if { = - }return , nil}// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.func ( string) (int, error) {const = "Atoi" := len()ifintSize == 32 && (0 < && < 10) ||intSize == 64 && (0 < && < 19) {// Fast path for small integers that fit int type. := if [0] == '-' || [0] == '+' { = [1:]iflen() < 1 {return0, syntaxError(, ) } } := 0for , := range []byte() { -= '0'if > 9 {return0, syntaxError(, ) } = *10 + int() }if [0] == '-' { = - }return , nil }// Slow path for invalid, big, or underscored integers. , := ParseInt(, 10, 0)if , := .(*NumError); { .Func = }returnint(), }// underscoreOK reports whether the underscores in s are allowed.// Checking them in this one function lets all the parsers skip over them simply.// Underscore must appear only between digits or between a base prefix and a digit.func ( string) bool {// saw tracks the last character (class) we saw: // ^ for beginning of number, // 0 for a digit or base prefix, // _ for an underscore, // ! for none of the above. := '^' := 0// Optional sign.iflen() >= 1 && ([0] == '-' || [0] == '+') { = [1:] }// Optional base prefix. := falseiflen() >= 2 && [0] == '0' && (lower([1]) == 'b' || lower([1]) == 'o' || lower([1]) == 'x') { = 2 = '0'// base prefix counts as a digit for "underscore as digit separator" = lower([1]) == 'x' }// Number proper.for ; < len(); ++ {// Digits are always okay.if'0' <= [] && [] <= '9' || && 'a' <= lower([]) && lower([]) <= 'f' { = '0'continue }// Underscore must follow digit.if [] == '_' {if != '0' {returnfalse } = '_'continue }// Underscore must also be followed by digit.if == '_' {returnfalse }// Saw non-digit, non-underscore. = '!' }return != '_'}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.