2015-01-09 7 views
0
var x = jokes[arc4random_uniform(UInt32(jokes.count))] 

Почему эта строка кода произвести такую ​​ошибку?Не удалось найти перегрузки «INIT», которые принимают прилагаемое аргумент

Когда этот код написан

var x = jokes[Int(arc4random()%jokes.count)] 

Эта ошибка появляется

Int is not convertible to UInt32 
+0

Возможный дубликат [ Сбой при сдаче результата arc4random() в Int] (http://stackoverflow.com/questions/24087518/crash-when-casting-the-result-of-arc4random-to-int) – Sulthan

ответ

3

Подстрочный индекс массива принимает Int, а не UInt32. ПЕД преобразовать обратно:

let x = jokes[Int(arc4random_uniform(UInt32(jokes.count)))] 

Если это становится немного шумным для вас, вы можете создать функцию, чтобы справиться с этим:

func randomValueLessThan(x: Int) -> Int { 
    return Int(arc4random_uniform(UInt32(x))) 
} 

Или вы можете расширить массив, чтобы помочь:

extension Array { 
    func uniformSelection() -> T { 
     return self[Int(arc4random_uniform(UInt32(self.count)))] 
    } 
} 

EDIT: это стоит копать немного глубже в Int(arc4random()%jokes.count) случае, потому что вы могли бы возникнуть соблазн исправить его неправильно, и он показывает, почему Swift работает так, как он делает. начало

Давайте с вашей версией

let n = Int(arc4random() % jokes.count) 
// => Could not find an overload for 'init' that accepts the supplied arguments 

Это немного сбивает с толку. Давайте упростим, чтобы увидеть проблему.

let n = arc4random() % jokes.count 
// => Cannot invoke '%' with an argument list of type '(UInt32, Int)' 

Это должно быть яснее. arc4random возвращает UInt32 и jokes.count() возвращает Int. Вы не можете использовать разные типы модулей. Вам нужно доставить их туда же. Ну, мы хотим Int, правильно? Похоже на то, что:

let n = Int(arc4random()) % jokes.count // WARNING!!!! Never ever do this!!!! 

Почему Apple настолько педантична и заставляет нас делать это вручную? Не мог ли компилятор просто использовать его автоматически? Ну, приведенный выше код будет отлично работать на 64-битном процессоре и сбой примерно в два раза на 32-битном процессоре. Это потому, что, позвонив Int(), вы обещаете, что значение будет всегда быть в диапазоне Int. А на 32-битном процессоре это 32-разрядный диапазон. Но arc4random возвращает значение во всем 32-битном неподписанном диапазоне, который включает в себя множество номеров, которые не будут вписываться в Int. Blam! (Или, если вы отключите проверку границ, то это просто искажает ваши номера, как в C, что не лучше.)

Вот почему Swift придирчив к целым преобразованиям. Вы должны быть абсолютно уверены, когда будете считать, что это безопасное преобразование. Вы не должны просто посыпать их, пока они не скомпилируются.

Это, конечно, вы никогда не должны использовать модуль на arc4random. But that's a different question.

В качестве еще одной заметки вы заметите, что числовое литье в randomValueLessThan() создает множество возможных недопустимых ситуаций. Если вы пройдете число меньше 0, вы потерпите крах (это не должно удивлять, хотя).Если вы пройдете число больше UInt32.Max, вы также столкнетесь, что несколько удивительно, но маловероятно в большинстве кодов. Дело в том, что добавив эти отливки, мы сделали randomValueLessThan a частичной функцией. Он не определяется по всему диапазону входных данных (это «домен»). В программировании «реальной жизни» мы делаем это все время, и мы просто надеемся, что он никогда нас не укусит. Но Swift пытается помочь нам укусить еще меньше, сделав его более очевидным, когда вы нарушаете безопасность типов.

uniformSelection имеет аналогичную проблему. Он определен только для массивов с менее чем UInt32.Max элементами. Они иногда кажутся бессмысленными угловыми случаями, и они до тех пор, пока они не станут неожиданными, и ваша программа выйдет из строя. (Array.subscript также является частичной функцией, так как он не определен для значений вне диапазона массива.Я на самом деле предложил Apple, что Array.subscript вернуть дополнительный вариант для учета этого. Вероятно, было бы разумно игнорировать меня.)

+0

вы можете добавить ответ для arc4random а также с использованием модуля – user3526002

+1

Вы никогда не должны использовать 'arc4random' с модулем. Это подрывает ваши ценности. Причина, по которой компилятор терпит неудачу, но то же самое. Вы должны явно преобразовывать значения между 'Int' и' UInt32'. –

+0

(я добавлю немного больше об этом, но это образовательный момент.) –

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