У меня есть простая структура и модель данных:
struct Phone: Identifiable {
var id = UUID()
var size: String
var model: String
var price: Int
}
let PhoneData = [
Phone(size: "L", model: "New", price: 500),
Phone(size: "X", model: "Old", price: 400),
Phone(size: "X", model: "New", price: 600),
Phone(size: "M", model: "New", price: 650)
]
Я хочу создать общую функцию, которая принимает входные данные, будь то размер, модель или цена, и возвращает ее значение.
я пробовал это
func returnWhatever<T>(whichProperty: T) -> Any {
let phone = PhoneData[0]
return phone.T
}
Но он печатает «Значение типа« Телефон »не имеет члена« Т »».
Я не хочу иметь три функции для каждого свойства модели данных, как эта для размера:
func returnWhatever() -> String {
let phone = PhoneData[0]
return phone.size
}
Не могли бы вы мне помочь, пожалуйста?
Очень незначительное замечание, но я бы посоветовал начинать PhoneData
с заглавной буквы. Я бы предложил phoneData
или, поскольку это не Data
, возможно, phoneArray
или просто phones
.
Вам нужна функция, которая возвращает значения только для первого элемента массива, какая польза от такой функции? И почему бы не использовать такие свойства, как phoneData.first?.size
, phoneData.first?.model
и phoneData.first?.price
@ Роб, да, ты прав, я делал это в спешке, моя ошибка
@Joakim, это часть более крупного проекта, это упрощенный пример, я просто ищу лучшее решение, вместо того, чтобы использовать 3 функции, я хочу использовать 1
И с моим предложением вы не будете использовать никакую функцию, а только свойства. Я просто не вижу, что функция, которую вы хотите, добавляет какую-либо ценность, но, возможно, я что-то упускаю
да, ваше предложение полностью справедливо. однако в нашем проекте мы используем еще один параметр и несколько условий, просто ищем здесь принцип. но спасибо!!
Ваш вопрос не имеет смысла, как есть. Может ты об этом спрашиваешь?
Phone.propertyOfSomePhone(\.price)
extension Phone {
static let all: [Self] = [
.init(size: "L", model: "New", price: 500),
.init(size: "X", model: "Old", price: 400),
.init(size: "X", model: "New", price: 600),
.init(size: "M", model: "New", price: 650)
]
static func propertyOfSomePhone<Property>(_ property: (Self) -> Property) -> Property {
property(all[0])
}
}
позвольте мне немного перефразировать: я хочу, чтобы функция возвращала значение (String или Int) на основе ввода (whatProperty), которое является свойством телефона (Size, Model, Price): поэтому я называю это returnWhatever ( whichProperty: size) и возвращает «L» или returnWhatever(whatProperty: price) и возвращает 500. И значения взяты из телефона в позиции 0 в массиве.
Это не то, что говорит ваш вопрос, но это то, что в моем ответе.
да, вы правы, моя ошибка, извините, спасибо за вашу помощь!
Вы можете использовать выражение key-path:
struct Phone: Identifiable {
var id = UUID()
var size: String
var model: String
var price: Int
}
let phones = [
Phone(size: "L", model: "New", price: 500),
Phone(size: "X", model: "Old", price: 400),
Phone(size: "X", model: "New", price: 600),
Phone(size: "M", model: "New", price: 650)
]
func returnWhatever<T>(_ property: KeyPath<Phone, T>) -> T {
let phone = phones[0]
return phone[keyPath: property]
}
А потом
let value = returnWhatever(\.price)
Или, как сказал Джесси , вы можете использовать замыкание, потому что Swift 5.2 позволяет использовать ключевые пути в качестве функций ( см. SE-0249). Таким образом:
func returnWhatever<T>(_ block: (Phone) -> T) -> T {
let phone = phones[0]
return block(phone)
}
И снова этот синтаксис выражения ключ-путь работает:
let value = returnWhatever(\.price)
большой! спасибо за подробное описание, выражение key-path для меня новая тема
size
иmodel
оба являютсяString
s.