2015-04-26 2 views
3

А функции типа данных у меня занимают мин, uint16 макс параметров и в некоторой точке перебирает числовой диапазон. Однако если max2^16-1 (и это допустимый прецедент), то переполнение прерывает логику цикла. Ниже приведен пример кода, демонстрирующий проблему с uint8:итерационных границ такой же, как

package main 

import "fmt" 

func iter(min, max uint8) { 
    for i := min; i <= max; i++ { 
     fmt.Printf("%d, ", i) 
    } 
} 

func main() { 
    iter(0, 255) 
} 

Как вы можете видеть, программа никогда не заканчивается. Аналогичный вопрос задавали в another question, но решение точно показывает ту же проблему, что и у меня.

Мое мышление сейчас является преобразование переменной цикла в uint32, похожее на это:

package main 

import "fmt" 

func iter(min, max uint8) { 
    for i := uint16(min); i <= uint16(max); i++ { 
     fmt.Printf("%d, ", i) 
    } 
} 

func main() { 
    iter(0, 255) 
} 

Однако, это, кажется, неуклюжее решение, которое не будет работать на uint64 или что-то самое большое uintN тип. Чувствуется, что я пропускаю что-то очень основное. Руководство?

Я знаю Brad Fitz's Iter solution, но, кажется, добавляет ненужные накладные расходы. Это правда?

+1

У меня есть Hacky решение для вас, а не переборе до 'max' включительно, итерацию до' max' эксклюзив. Таким образом, переполнение никогда не достигается. –

+0

Полагаю, это стиль, который вы предлагаете? https://gist.githubusercontent.com/didenko/ed5144f6349656c683dc/raw/3a4b2d1c565819f54604a97409e6b6b0d0fe50b8/max_special.go –

+0

@ VladDidenko: Какой результат вы получаете для 'iter (42, 7)'? https://gist.githubusercontent.com/didenko/ed5144f6349656c683dc/raw/3a4b2d1c565819f54604a97409e6b6b0d0fe50b8/max_special.go – peterSO

ответ

3

Например, для uint8,

package main 

import "fmt" 

func iter(min, max uint8) { 
    { 
     min, max := uint(min), uint(max) 
     for i := min; i <= max; i++ { 
      fmt.Printf("%d, ", i) 
     } 
    } 
} 

func main() { 
    iter(0, 255) 
} 

Для uint64,

package main 

import "fmt" 

func iter(min, max uint64) { 
    for i := min; i <= max; i++ { 
     fmt.Printf("%d, ", i) 
     if i == max { 
      break 
     } 
    } 
} 

func main() { 
    iter(^uint64(0)-2, ^uint64(0)) 
} 

Выход:

18446744073709551613, 18446744073709551614, 18446744073709551615 

Добавление:

Вот моя версия Dave C's suggestion.

package main 

import "fmt" 

func iter(min, max uint64) { 
    for i, next := min, min <= max; next; i, next = i+1, i < max { 
     fmt.Printf("%#016[1]x ", i) 
    } 
    fmt.Println() 
} 

func main() { 
    const maxUint64 = ^uint64(0) 
    iter(0, 3) 
    iter(10, 9) 
    iter(maxUint64-2, maxUint64) 
} 

Выход:

0x0000000000000000 0x0000000000000001 0x0000000000000002 0x0000000000000003 
0xfffffffffffffffd 0xfffffffffffffffe 0xffffffffffffffff 
+0

Обратите внимание, что в последнем случае вам нужно не использовать 'continue' перед условным. Также условие 'for' становится избыточным, поэтому просто для i: = min; ; i ++ {'если хотите. –

+0

Есть ли существенная разница между первой версией ответа и той, которая предлагается в вопросе? Второй, после предложения Дейва может выглядеть так: https: //gist.githubusercontent.com/didenko/ed5144f6349656c683dc/raw/e8d14b04700d9a26a4c5140219c811ec4ccb7a5c/check_in_body.go Меня беспокоит необходимость запоминать опасность «продолжения» перед тестом, поэтому, если вызов функции не является проблемой, версия в вопросительных комментариях выглядит несколько предпочтительнее. Я что-то пропустил? –

+0

@DaveC: всякий раз, когда вы меняете код, вы должны быть уверены, что не вводите ошибки. Вы можете сделать это разными способами. Например, введя errant 'continue' или следуя вашему предложению об удалении условия' for' 'i <= max', которое будет изменять поведение функции' iter' всякий раз, когда 'min> max'. – peterSO

Смежные вопросы