#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 по кортежам и уделил больше внимания разделу о временных типах. Действительно ценю ваше предложение, понимание и предысторию. Спасибо!