Листинг в Главе 13-04 Rust Book содержит следующий цикл for:
for i in 12..buffer.len() {
let prediction = coefficients
.iter()
.zip(&buffer[i - 12..i])
.map(|(&c, &s)| c * s as i64)
.sum::<i64>()
}
Я понимаю, что это делает, за исключением бита «i - 12..i». Я не знал, что можно вычесть диапазон из целого числа и получить... другой диапазон?
Я использовал Rust Playground, чтобы увидеть, как этот синтаксис работает эмпирически:
println!("\"3 - 3..4\": {:?}", 3 - 3..4);
println!("\"3 - 3..3\": {:?}", 3 - 3..3);
println!("\"3 - 3..2\": {:?}", 3 - 3..2);
println!("\"3 - 3..1\": {:?}", 3 - 3..1);
println!("\"3 - 3..0\": {:?}", 3 - 3..0);
Что печатает:
"3 - 3..4": 0..4
"3 - 3..3": 0..3
"3 - 3..2": 0..2
"3 - 3..1": 0..1
"3 - 3..0": 0..0
Следовательно, наивным ответом будет то, что вычитание диапазона из целого числа даст диапазон, который начинается с нуля и заканчивается разницей между целым числом и длиной (положительной или отрицательной) диапазона.
Это хорошее объяснение? Какая черта в std::ops::Range делает возможным этот синтаксис?
О, приятно знать
Это связано с приоритетом операторов, который определяет, какие операторы связываются сильнее, чем другие, когда отсутствуют скобки, т. е. если вы пишете a + b * c
, интерпретируется ли это как (a + b) * c
или a + (b * c)
.
В этом случае вы просто используете минус и диапазон, но вопрос тот же, так a - b..c
интерпретируется как (a - b)..c
или a - (b..c)
? Это бывший. Поэтому, когда вы пишете 3 - 3..4
, это интерпретируется как (3 - 3)..4
, поэтому в результате получается диапазон, идущий от 0..4
.
Если вы попытаетесь явно заключить диапазон в круглые скобки, например 3 - (3..4)
, то компилятор выдаст ошибку, говоря, что Sub<Range<{integer}>> for {integer}
на самом деле вообще не реализован.
Если вы сомневаетесь, заключите операцию в круглые скобки.
Просто совет: вы можете использовать макрос
dbg!(...)
, чтобы избежать повторения. Например.dbg!(3 - 3..4)
который выводит:3 - 3..4 = 0..4