Пакеты параметров типа: как вернуть кортеж вместо массива?

Для начала у меня есть этот код, который работает совершенно нормально:

protocol ComponentAccessible {}

extension ComponentAccessible { 
    func components<each T>(_ keyPaths: repeat KeyPath<Self, each T>) -> (repeat each T) {
        { (repeat self[keyPath: each keyPaths]) } 
    } 
}

// MARK: - Usage 

extension URL: ComponentAccessible {}
url.components(\.scheme, \.host, \.path)

Но теперь я хочу попробовать немного другой подход (используя PartialKeyPath):

extension ComponentAccessible {
    func components<each T>(_ keyPaths: PartialKeyPath<Self>...) -> (repeat each T) {
        keyPaths.map { self[keyPath: $0] }
    }
}

Это не компилируется, потому что я возвращаю массив, а не кортеж.

Я считаю, что проблема заключается в разнице между PartialKeyPath и KeyPath, поскольку PartialKeyPath не знает тип, на который он ссылается, что делает невозможным (или, по крайней мере, трудным) разрешение <each T> как типа. В чем причина использования PartialKeyPath?

Roy Rodney 27.06.2024 10:09

@RoyRodney Синтаксическое упражнение 😃

Roman 27.06.2024 11:35

Как отметил Рой, использование такого частичного ключевого пути по своей сути не является типобезопасным. Так что это просто невозможно.

Sweeper 27.06.2024 13:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, это не типобезопасно. PartialKeyPath не знает тип значения ключевого пути, только тип корня. Итак, чтобы иметь возможность вернуть (repeat each T), нужно провести кастинг.

Во-вторых, тип keyPaths, PartialKeyPath<Self>... не является расширением пакета. Это должно быть расширение пакета, чтобы вы могли вернуть кортеж с соответствующим количеством элементов.

Итак, вам нужно, чтобы пакет типов each T появлялся где-то в типе keyPaths, чтобы вы могли написать расширение пакета для типа keyPaths, т. е. вызывающая сторона должна так или иначе передать те типы, которые ему нужны.

На этом этапе вы должны понимать, что вам следует просто продолжать использовать KeyPath<Root, Value>, потому что вы можете напрямую использовать each T там. Если вам нужно «синтаксическое упражнение», вы можете взять пары PartialKeyPath<Self> и метатипа.

extension ComponentAccessible {
    func components<each T>(keyPaths: repeat (PartialKeyPath<Self>, (each T).Type)) -> (repeat each T) {
        (repeat self[keyPath: (each keyPaths).0] as! each T)
    }
}

Вы также не можете вернуть кортеж Any. Хотя вы можете «обмануть» компилятор, заставив его думать, что вы используете пакет типов, написав псевдоним типа, компилятор все равно «увидит, что вы делаете» позже. Это не работает:

typealias A<X> = Any
typealias PKP<X, Y> = PartialKeyPath<X>
// now you can write (repeat A<each T>) to mean a variadic tuple of Anys, but...

extension ComponentAccessible {
    // the compiler can see that you are not using T anywhere,
    // and no, you cannot add a dummy metatype parameter with a default value
    // parameter pack parameters cannot have default values
    func components<each T>(keyPaths: repeat PKP<Self, each T>) -> (repeat each A<each T>) {
        (repeat self[keyPath: each keyPaths])
    }

    // the compiler cannot form the constraint that keyPaths should have the same shape as the return type
    func components<each T>(keyPaths: repeat PKP<Self, each T>) -> (repeat each T) {
        (repeat self[keyPath: each keyPaths] as! each T)
    }
}

Другие вопросы по теме