Если у вас есть это:
var s uint = 33
fmt.Println(1 << s)
Тогда применяется цитируемая часть:
Если левый операнд неконстантного выражения сдвига является нетипизированной константой, онсначала неявно преобразуется в тип, который он принял бы, если бы выражение сдвига было заменено только его левым операндом.
Поскольку s
не является константой (это переменная), следовательно, 1 >> s
являетсявыражение непостоянного сдвига.А левый операнд - 1
, который является нетипизированной константой (например, int(1)
будет типизированной константой), поэтому он преобразуется в тип, который он получит, если выражение будет просто 1
вместо 1 << s
:
fmt.Println(1)
В приведенном выше примере нетипизированная константа 1
будет преобразована в int
, поскольку это ее тип по умолчанию.Тип констант по умолчанию: Spec: Константы:
Нетипизированная константа имеет тип по умолчанию , который является типом, в который константа неявно преобразуется вконтексты, где требуется типизированное значение, например, в кратком объявлении , например i := 0
, где нет явного типа.Тип по умолчанию для нетипизированной константы - bool
, rune
, int
, float64
, complex128
или string
соответственно, в зависимости от того, является ли она логической, рунической, целой, с плавающей точкой, сложнойили строковая константа.
И результат вышеизложенного зависит от архитектуры.Если int
равно 32 битам, это будет 0
.Если int
равно 64 битам, это будет 8589934592
(потому что смещение 1
бита 33 раза сместит его из 32-битного int
числа).
На игровой площадке Go,размер int
составляет 32 бита (4 байта).См. Этот пример:
fmt.Println("int size:", unsafe.Sizeof(int(0)))
var s uint = 33
fmt.Println(1 << s)
fmt.Println(int32(1) << s)
fmt.Println(int64(1) << s)
Вышеуказанные выходы (попробуйте на Go Playground ):
int size: 4
0
0
8589934592
Если я запустил вышеуказанное приложение на моем 64-В битовом компьютере вывод:
int size: 8
8589934592
0
8589934592
Также см. Блог Go: Константы о том, как константы работают в Go.
Обратите внимание, что если вы напишите 1 << 33
это не то же самое, это не выражение неконстантного сдвига, к которому применяется ваша цитата: «левый операнд выражения неконстантного сдвига» .1<<33
является выражением с постоянным сдвигом, которое вычисляется в «постоянном пространстве», и результат будет преобразован в int
, который не вписывается в 32-битный int
, следовательно, ошибка времени компиляции.Он работает с переменными, потому что переменные могут переполняться.Константы не переполняются:
Числовые константы представляют собой точные значения произвольной точности и не переполняются.
См. Как Go выполняет арифметику для констант?
Обновление:
Отвечая на ваше добавление: преобразование из int16
в int8
просто сохраняет младшие 8 бит.И целые числа представлены в формате 2 в дополнении , где старший бит равен 1
, если число отрицательное.
Это подробно описано в Спецификация: Преобразования:
При преобразовании между целочисленными типами, если значение является целым числом со знаком, оно расширяется до неявной бесконечной точности;в противном случае это ноль продлен. Затем оно усекается для соответствия размеру типа результата. Например, если v := uint16(0x10F0)
, то uint32(int8(v)) == 0xFFFFFFF0
.Преобразование всегда дает действительное значение;нет никаких признаков переполнения.
Так что при преобразовании значения int16
в int8
, если номер источника имеет 1
в битовой позиции 7 (8-й бит), результат будетбыть отрицательным, даже если источник не был отрицательным.Точно так же, если источник имеет 0
в битовой позиции 7, результат будет положительным, даже если источник отрицательный.
См. Этот пример:
for _, v := range []int16{4336, -129, 8079} {
fmt.Printf("Source : %v\n", v)
fmt.Printf("Source hex: %4x\n", uint16(v))
fmt.Printf("Result hex: %4x\n", uint8(int8(v)))
fmt.Printf("Result : %4v\n", uint8(int8(v)))
fmt.Println()
}
Вывод (попробуйтена игровой площадке Go ):
Source : 4336
Source hex: 10f0
Result hex: f0
Result : -16
Source : -129
Source hex: ff7f
Result hex: 7f
Result : 127
Source : 8079
Source hex: 1f8f
Result hex: 8f
Result : -113
См. связанные вопросы:
При приведении int64 к uint64 знак сохраняется?
Форматировать печать 64-битного целого числа -1 как шестнадцатеричное отклонение между golang и C