import CasePaths
extension CasePathable where AllCasePaths: CasePathReflectable<Self> {
func associatedValue<T: CasePathable>() -> T? where T.AllCasePaths: CasePathReflectable<T> {
let caseKeyPath = Self.allCasePaths[self]
return self[case: caseKeyPath] as? T
}
}
Nota: estritamente falando, não é necessária familiaridade com a biblioteca swift-case-paths do PointFree que estou usando aqui. Fundamentalmente, minha pergunta diz respeito somente ao Swift em si.
Então, dada a função correta acima, o objetivo é aplicá-la recursivamente, para recuperar o valor aninhado mais profundo.
Mas como lidar com os tipos aqui? Porque cada valor associado pode ser um tipo diferente. O problema é que a associatedValue()
função retorna um genérico T
, que deve ser especificado. Mas para uma solução geral, não podemos saber cada um T
com antecedência.
Darei um exemplo concreto para maior contexto:
@CasePathable
enum A {
case a(B)
case smthA
}
@CasePathable
enum B {
case b(C)
case smthB
}
@CasePathable
enum C {
case c
case smthC
}
let aValue: A = .a(.b(.c))
let bAssValue: B = aValue.associatedValue()! // .b(.c))
let cAssValue: C = bAssValue.associatedValue()! // .c
Assumirei que cada caso de enumeração terá no máximo 1 valor associado.
Como você não conhece os tipos intermediários, você precisa trabalhar com os tipos existenciais.
any CasePathable
não é possível capturar a restrição dewhere AllCasePaths: CasePathReflectable<Self>
, então você precisa introduzir um protocolo extra para representar esse tipo.Todas as suas enumerações devem estar em conformidade com
ReflectableCasePathable
.Você também precisa de uma versão
associatedValue
que retorne umany ReflectableCasePathable
.Note que
associatedValue
não precisa depender daAllCasePaths: CasePathReflectable<Self>
restrição. Em vez disso, pode depender doCasePathIterable
protocolo, onde você pode encontrar o caminho do caso correto por iteração.Então você não precisa introduzir o novo protocolo, mas estou divagando.
Em qualquer caso, você pode simplesmente chamar isso em um loop.
Considere também este design alternativo, que permite extrair o valor não associado à enumeração no nível "mais baixo".
Isso permite que você faça coisas como esta: