Массив сокращений: Xcode Swift: выражение слишком сложное, чтобы его можно было решить за разумное время

#arrays #swift #xcode #closures #tuples

#массивы #swift #xcode #замыкания #Кортежи

Вопрос:

Я делаю простые преобразования (например, имперский в метрический). Я создал массив кортежей с элементами (String, Closure). Это позволяет мне помещать строку для преобразования (например, «мили в километры» в элемент управления выбора и ссылаться на соответствующую формулу в одной строке, передавая значение для преобразования. Проблема, с которой я сталкиваюсь, заключается в том, что я использую сокращение закрытия $ 0. Я получаю сообщение об ошибке «Выражение слишком сложное для решения за разумное время».

Вот объявление и код, которые работают:

Объявлено с помощью свойств ViewController ниже начального оператора класса:

 var formulaTuple = [(convString: String, convFormula: ((Double) -> Double))]()
  

Назначается в viewDidLoad()

     formulaTuple = [("miles to kilometers", {(a: Double) -> Double in return (a / 0.62137) }),
               ("kilometers to miles", {(a: Double) -> Double in return (a * 0.62137) }),
               ("feet to meters", {(a: Double) -> Double in return (a / 3.2808) }),
               ("yards to meters", {(a: Double) -> Double in return (a / 1.0936) }),
               ("meters to feet", {(a: Double) -> Double in return (a * 3.2808) }),
               ("meters to yards", {(a: Double) -> Double in return (a * 1.0936) }),
               ("inches to centimeters", {(a: Double) -> Double in return (a / 0.39370) }),
               ("centimeters to inches", {(a: Double) -> Double in return (a * 0.39370) }),
               ("fahrenheit to celsius", {(a: Double) -> Double in return ((a - 32) * (5/9)) }),
               ("celsius to fahrenheit", {(a: Double) -> Double in return (a * (9/5)   32) }),
               ("quarts to liters", {(a: Double) -> Double in return (a / 1.05669) }),
               ("liters to quarts", {(a: Double) -> Double in return (a * 1.05669) }) ]
  

И рабочий вызов в коде, где row — это строка в сборщике, на которую был нажат, inputValue — это то, что передается для преобразования, а outputValue — результат преобразования.

outputValue = formulaTuple[строка].convFormula(входное значение)

Проблема возникает, когда я пытаюсь урезать объявление, используя этот синтаксис в viewDidLoad() вместо synatax выше:

     formulaTuple = [("miles to kilometers", {$0 / 0.62137 }),
                    ("kilometers to miles", {$0 * 0.62137 }),
                    ("feet to meters", {$0 / 3.2808 }),
                    ("yards to meters", {$0 / 1.0936 }),
                    ("meters to feet", {$0 * 3.2808 }),
                    ("meters to yards", {$0 * 1.0936 }),
                    ("inches to centimeters", {$0 / 0.39370}),
                    ("centimeters to inches", {$0 * 0.39370 }),
                    ("fahrenheit to celsius", {($0 - 32) * (5/9) }),
                    ("celsius to fahrenheit", {$0 * (9/5)   32 }),
                    ("quarts to liters", {$0 / 1.05669 }),
                    ("liters to quarts", {$0 * 1.05669 }) ]
  

Я думал, что это будет более плавным, но, похоже, это нарушает Xcode. Мысли? Является ли мой подход принципиально несостоятельным и был бы рекомендован другой?
Спасибо!

Ответ №1:

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

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

 let temp: [(String, (Double) -> Double)] = [
            ("miles to kilometers", {$0 / 0.62137 }),
            ("kilometers to miles", {$0 * 0.62137 }),
            ("feet to meters", {$0 / 3.2808 }),
            ("yards to meters", {$0 / 1.0936 }),
            ("meters to feet", {$0 * 3.2808 }),
            ("meters to yards", {$0 * 1.0936 }),
            ("inches to centimeters", {$0 / 0.39370}),
            ("centimeters to inches", {$0 * 0.39370 }),
            ("fahrenheit to celsius", {($0 - 32) * (5/9) }),
            ("celsius to fahrenheit", {$0 * (9/5)   32 }),
            ("quarts to liters", {$0 / 1.05669 }),
            ("liters to quarts", {$0 * 1.05669 })
]

formulaTuple = temp
  

Альтернативный ответ

Кортежи действительно предназначены для временного хранения и передачи нескольких результатов обратно из функции. Возможно, вы захотите рассмотреть возможность использования a struct в качестве типа для значений вашего массива:

 struct Conversion {
    let string: String
    let formula: (Double) -> Double
}

var conversions = [Conversion]()

conversions = [
    Conversion(string: "miles to kilometers", formula: {$0 / 0.62137 }),
    Conversion(string: "kilometers to miles", formula: {$0 * 0.62137 }),
    Conversion(string: "feet to meters", formula: {$0 / 3.2808 }),
    Conversion(string: "yards to meters", formula: {$0 / 1.0936 }),
    Conversion(string: "meters to feet", formula: {$0 * 3.2808 }),
    Conversion(string: "meters to yards", formula: {$0 * 1.0936 }),
    Conversion(string: "inches to centimeters", formula: {$0 / 0.39370}),
    Conversion(string: "centimeters to inches", formula: {$0 * 0.39370 }),
    Conversion(string: "fahrenheit to celsius", formula: {($0 - 32) * (5/9) }),
    Conversion(string: "celsius to fahrenheit", formula: {$0 * (9/5)   32 }),
    Conversion(string: "quarts to liters", formula: {$0 / 1.05669 }),
    Conversion(string: "liters to quarts", formula: {$0 * 1.05669 })
]

outputValue = conversions[row].formula(inputValue)
  

Swift намного счастливее с этим, и temp обходной путь не нужен.

Комментарии:

1. Структура работала очень хорошо. Я перечитал документы Swift по кортежам и уделил больше внимания разделу о временных типах. Действительно ценю ваше предложение, понимание и предысторию. Спасибо!