In strconv.ParseInt, what do the base and bitSize arguments control?
answer
- two numbers, two unrelated jobs
- the radix, and how wide the answer may be
- 0 means read the prefix yourself
- the return type never changes with the width
basics
~20 sbase is the radix, 2 through 36, or 0 to infer it from a 0x, 0o, 0b or leading-zero prefix. bitSize says which signed width the value must fit: 0, 8, 16, 32 or 64. The result is always an int64.
solid answer
~50 sThe signature is `func ParseInt(s string, base int, bitSize int) (int64, error)`. `base` is the radix; it must be 0 or between 2 and 36. Base 0 is special: the prefix decides, so `0x`/`0X` is hex, `0b` binary, `0o` octal, a bare leading `0` is octal too, and underscore digit separators such as `1_000` are accepted *only* at base 0. With an explicit base the prefix is not stripped, so `ParseInt("0x1f", 16, 64)` is a syntax error. `bitSize` is a range check, not a return type: 0 means the value must fit `int`, and 8, 16, 32 and 64 mean the corresponding signed types. A value too large gives `strconv.ErrRange` together with the clamped maximum-magnitude value for that width. Doing the range check at the parse step is why `strconv.ParseUint(v, 10, 16)` is the neat way to accept a TCP port.
code
go · 4 linesstrconv.ParseInt("0x1f", 0, 64) // 31, nil: prefix decides the base
strconv.ParseInt("0x1f", 16, 64) // 0, ErrSyntax: x is not a hex digit
strconv.ParseInt("1_000", 0, 64) // 1000, nil: separators need base 0
strconv.ParseInt("300", 10, 8) // 127, ErrRange: clamped to int8's maxgo deeper
Know that ParseInt exists for cases Atoi cannot handle: other bases and a width limit. Be able to say that the two extra arguments are the radix and the target size, and that the result comes back as an int64.
This is your level's question. Explain base 0 prefix inference, the underscore rule that goes with it, bitSize as a range check rather than a type, and the fact that an out-of-range parse returns the clamped maximum alongside ErrRange.
Show how you use bitSize as validation instead of writing bounds checks after the fact, and explain what goes wrong operationally when the range error is ignored: a saturated setting reads as a plausible number rather than an obvious zero.
Set the house rule for configuration parsing: explicit base 10 for human-written values so a zero-padded string never silently becomes octal, widths chosen to match the domain, and a single helper so every service reports a bad setting the same way at startup.
## The signature ```go func ParseInt(s string, base int, bitSize int) (i int64, err error) ``` Three inputs, two outputs, and the two integer inputs do completely different jobs. Candidates who have only ever used `strconv.Atoi` tend to guess that `bitSize` changes the return type; it does not. `ParseInt` always returns an `int64`. ## base: the radix, or 0 for "read the prefix" `base` must be 0, or a value from 2 through 36. Digits above 9 are the letters `a` to `z`, case-insensitively, so base 36 gives you `z` = 35. Base 0 means *infer the base from the string's own prefix*, exactly the way a Go source literal would be read: | input | base 0 result | | --- | --- | | `"42"` | 42, decimal | | `"0x2a"` or `"0X2A"` | 42, hexadecimal | | `"0b101010"` | 42, binary | | `"0o52"` | 42, octal | | `"052"` | 42, legacy octal from the bare leading zero | | `"1_000"` | 1000, underscores accepted | Two consequences catch people out. First, **underscore separators are permitted only when base is 0** - `ParseInt("1_000", 10, 64)` is a syntax error. Second, **an explicit base does not strip the prefix**: at base 16 the character `x` in `"0x1f"` is not a hex digit, so you get `strconv.ErrSyntax`. Strip the prefix yourself or pass base 0. And a config value like `"010"` read at base 0 quietly means 8, which is a real source of surprise when someone zero-pads a setting for alignment - if a human writes the value, prefer an explicit base 10. An out-of-domain base such as 1 or 37 returns a `*strconv.NumError` whose message says the base is invalid, rather than panicking. ## bitSize: a range check, not a type `bitSize` must be 0 or one of 8, 16, 32, 64, naming the signed type the parsed value has to fit: `int8`, `int16`, `int32`, `int64`, with 0 meaning `int`. The result still comes back as `int64`; you convert down yourself, and that conversion is safe precisely because the range has already been validated: ```go v, err := strconv.ParseInt(s, 10, 16) if err != nil { return err } var level int16 = int16(v) // cannot overflow: ParseInt already checked ``` When the digits are valid but the number does not fit, `ParseInt` does something worth remembering: it returns `strconv.ErrRange` **and** the maximum-magnitude value of that width and sign. `ParseInt("300", 10, 8)` gives `127` and an error. It does not truncate to the low bits (`300 & 0xFF` would be 44) and it does not return zero. Ignore the error and you get a saturated value, not an obviously wrong one. ## Using bitSize as validation Because the width check happens inside the parse, `bitSize` is often the cheapest bounds check you can write. A configuration loader reading a TCP port can say: ```go port, err := strconv.ParseUint(v, 10, 16) // 0..65535, checked at parse time ``` and skip a separate `if port > 65535` entirely. `ParseUint` has the same shape as `ParseInt` and rejects a leading `-` outright. This is the pattern to reach for when an environment string has a natural width: a port, a byte value, a percentage stored in an `int8`. ## How Atoi relates `strconv.Atoi(s)` is `ParseInt(s, 10, 0)` with a fast path for short strings and with the returned error's `Func` field renamed to `"Atoi"`. That is why Atoi rejects `1_000` and `0x1f`: base 10 is fixed, so neither separators nor prefixes apply. Reach for `ParseInt` when you need a non-decimal base, a width limit, or an `int64` result on a 32-bit platform; reach for `Atoi` for the plain decimal case, because it is shorter and returns an `int` directly. ## The whole family `ParseInt`, `ParseUint`, `ParseFloat` and `ParseBool` all take the string first and all return `(value, error)` with the same `*strconv.NumError` shape on failure. `ParseUint` takes the same base and bitSize arguments with unsigned widths; `ParseBool` takes neither. ## Answering well A good answer names both arguments in one sentence, then adds the two facts that separate use from understanding: base 0 means prefix inference and is the only base that accepts underscores, and bitSize is a range check whose failure returns a clamped value rather than zero. Mentioning that the return type is always `int64` regardless of bitSize usually settles the question.
- Why does strconv.ParseInt return an int64 even when bitSize is 8?One signature has to cover every width, so the widest type is the return type and `bitSize` is a validation parameter rather than a type parameter. You convert down yourself with `int8(v)`, and that conversion cannot overflow because ParseInt already rejected anything out of range.
- What is strconv.Atoi in terms of ParseInt?`Atoi(s)` is `ParseInt(s, 10, 0)` with a fast path for short strings and the error's `Func` field set to `"Atoi"`. Because the base is fixed at 10 it accepts no `0x` prefix and no underscore separators, and because it returns an `int` you skip the int64 conversion.
- How would you parse a TCP port from an environment variable in one call?`strconv.ParseUint(v, 10, 16)`. The 16-bit width makes 65535 the maximum, so anything larger comes back as `strconv.ErrRange` at the parse step and a leading minus is rejected as invalid syntax. No separate bounds check is needed afterwards.
- What happens if you pass a base of 1 or 37?You get a `*strconv.NumError` whose `Err` reports an invalid base, not a panic. Valid bases are 0 and 2 through 36, where digit values above 9 are spelled with the letters a through z, case-insensitively.
saying these in an interview costs you the question
- Says base 0 means decimal
- Thinks bitSize changes the returned type
- Believes an out-of-range value is truncated to the low bits
- Passes base 16 for a string that still carries its 0x prefix
- Assumes underscore separators work at any base
- Converts the int64 down without checking the error first