Float64Bits preserves the underlying representation. The numeric value of the uint64 it returns has little significance. You’d typically use it when serializing floats, when wanting to make manual changes to the float’s representation, and so on.
uint64(f) cares about preserving the numeric value. As documented in the spec it will truncate towards zero and convert, preserving the same numeric value.
Your particular case however is hitting platform-specific behavior. This simplified version (
https://go.dev/play/p/GiQ2kuxol1d) will print 9223372036854775808 for u on x86, but 18446744073709551615 on arm. This is an area that frequently lands in undefined behavior in other languages.
For what it's worth, I don’t think the spec is particularly clear on this point.
From the spec:
> In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
From stdlib math docs:
> Max is the largest finite value representable by the type.
To me that would suggest that converting a float64 of MaxUint64 to a uint64 would result in MaxUint64 across implementations, but that doesn’t appear true in practice.