enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
Por exemplo, como posso fazer algo como:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
Exemplo resultante:
♠
♥
♦
♣
Respostas:
Swift 4.2+
Começando com o Swift 4.2 (com o Xcode 10), basta adicionar a conformidade do protocolo para
CaseIterable
se beneficiarallCases
. Para adicionar essa conformidade ao protocolo, basta escrever em algum lugar:Se a enum é sua, você pode especificar a conformidade diretamente na declaração:
Em seguida, o código a seguir imprimirá todos os valores possíveis:
Compatibilidade com versões anteriores do Swift (3.xe 4.x)
Se você precisar oferecer suporte ao Swift 3.x ou 4.0, poderá imitar a implementação do Swift 4.2 adicionando o seguinte código:
fonte
String
, em oposição à presente questão do Stack Overflow.Esta publicação é relevante aqui https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift
Essencialmente, a solução proposta é
fonte
Enum.Values(typeof(FooEnum))
mas exposto como um método de extensão (como mapear ou reduzir).FooEnum.values() :: values(EnumType -> [EnumType])
Eu criei uma função de utilitário
iterateEnum()
para iterar casos paraenum
tipos arbitrários .Aqui está o exemplo de uso:
Quais saídas:
Porém, isso é apenas para fins de depuração ou teste : isso depende de vários comportamentos não documentados do compilador Swift1.1; portanto, use-o por sua conta e risco.
Aqui está o código:
A ideia subjacente é:
enum
, excluindoenum
s com tipos associados, é apenas um índice de casos em que a contagem dos casos é2...256
idêntica aUInt8
quando257...65536
,UInt16
e assim por diante. Portanto, pode serunsafeBitcast
de tipos inteiros não assinados correspondentes..hashValue
de valores enum é o mesmo que o índice do caso..hashValue
dos valores de enumeração bitcasted de índice inválido é0
.Revisado para Swift2 e implementado idéias de elenco da resposta de @ Kametrixom :
Revisado para Swift3:
Revisado para Swift3.0.1:
fonte
withUnsafePointer
withMemoryRebound
epointee
coisas, então usar este por todos os meios. Caso contrário, eu evitaria.As outras soluções funcionam, mas todas elas assumem, por exemplo, o número possível de classificações e naipes, ou qual pode ser o primeiro e o último rank. É verdade que o layout de um baralho de cartas provavelmente não mudará muito no futuro próximo. Em geral, no entanto, é melhor escrever código que faça o mínimo de suposições possível. Minha solução:
Eu adicionei um tipo bruto à
Suit
enumeração, para que eu possa usarSuit(rawValue:)
para acessar osSuit
casos:Abaixo a implementação do
createDeck()
método do cartão .init(rawValue:)
é um inicializador disponível e retorna um opcional. Ao desembrulhar e verificar seu valor nas instruções while, não há necessidade de assumir o númeroRank
ouSuit
casos:Aqui está como chamar o
createDeck
método:fonte
Suit
. Você pode neste exemplo, mas o exercício foi feito para ajudá-lo a trabalhar com o queenums
lhe foi dado como se fosse de uma fonte externa.Eu tropecei nos bits e bytes e criei uma extensão que depois descobri que funciona muito semelhante à resposta do @rintaro . É usado assim:
O que é notável é que é utilizável em qualquer enumeração sem valores associados. Observe que isso não funciona para enumerações sem casos.
Como na resposta de @rintaro , esse código usa a representação subjacente de uma enumeração. Essa representação não está documentada e pode mudar no futuro, o que a quebraria. Eu não recomendo o uso disso na produção.
Código (Swift 2.2, Xcode 7.3.1, não está funcionando no Xcode 10):
Código (Swift 3, Xcode 8.1, não funciona no Xcode 10):
Não tenho idéia do porquê preciso
typealias
, mas o compilador reclama sem ele.fonte
withUnsafePointer
...pointee}
porwithUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
Você pode iterar através de uma enumeração implementando o
ForwardIndexType
protocolo.O
ForwardIndexType
protocolo requer que você defina umasuccessor()
função para percorrer os elementos.A iteração em um intervalo aberto ou fechado (
..<
ou...
) chamará internamente asuccessor()
função que permite que você escreva isso:fonte
successor()
método definido corretamente (primeira opção) eliminaria a necessidade deenum
ter um tipo associado. +1Esse problema agora é muito mais fácil. Aqui está a minha solução Swift 4.2:
Pré 4.2:
Eu gosto dessa solução que montei depois de encontrar " Compreensão da lista no Swift ".
Ele usa Int raws em vez de Strings, mas evita digitar duas vezes, permite personalizar os intervalos e não codifica os valores brutos.
Esta é uma versão do Swift 4 da minha solução original, mas veja a melhoria 4.2 acima:
fonte
Em princípio, é possível fazê-lo dessa maneira, assumindo que você não use a atribuição de valores brutos para os casos de enum:
fonte
enum ItWontWorkForThisEnum {case a, b, c}
Se você der ao enum um valor Int bruto, isso tornará o loop muito mais fácil.
Por exemplo, você pode usar
anyGenerator
para obter um gerador que possa enumerar seus valores:No entanto, isso parece um padrão bastante comum, não seria bom se pudéssemos enumerar qualquer tipo de enum simplesmente em conformidade com um protocolo? Bem, com o Swift 2.0 e extensões de protocolo, agora podemos!
Basta adicionar isso ao seu projeto:
Agora, sempre que você criar uma enumeração (desde que tenha um valor bruto Int), você poderá torná-la enumerável conforme o protocolo:
Se seus valores de enumeração não começarem com
0
(o padrão), substitua ofirstRawValue
método:A classe final do Suit, incluindo a substituição
simpleDescription
pelo protocolo CustomStringConvertible , mais padrão , terá a seguinte aparência:Sintaxe do Swift 3:
fonte
Atualizado para Swift 2.2 +
É um código atualizado para o formulário Swift 2.2 , resposta de Kametrixom
Para Swift 3.0+ (muito obrigado a @Philip )
fonte
Solução Swift 5:
fonte
Eu me vi fazendo
.allValues
muito em todo o meu código. Finalmente descobri uma maneira de simplesmente estar em conformidade com umIteratable
protocolo e ter umrawValues()
método.fonte
Xcode 10 com Swift 4.2
Chame-o
Impressões:
versões mais antigas
Por
enum
representarInt
Chame assim:
Impressões:
Por
enum
representarString
Chame-o
Impressões:
fonte
EDIT: Proposta de evolução rápida SE-0194 A coleção derivada de casos de enum propõe uma solução equilibrada para este problema. Vemos isso no Swift 4.2 e mais recente. A proposta também aponta para algumas soluções alternativas que são semelhantes às já mencionadas aqui, mas pode ser interessante ver, no entanto.
Também manterei minha postagem original por uma questão de integridade.
Essa é outra abordagem baseada na resposta de @ Peymmankh, adaptada ao Swift 3 .
fonte
Que tal agora?
fonte
Você pode tentar enumerar assim
fonte
static var enumerate = [Mercury, Venus, Earth, Mars]
, tornando-a uma resposta subpar em comparação com mais votado resposta stackoverflow.com/a/24137319/1033581return [Mercury, Venus, Mars]
em vez dereturn [Mercury, Venus, Earth, Mars]
return [.spades, .hearts, .clubs]
o compilador não dirá nada e, quando tentar usá-la no código, você obterá[TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]
- esse foi o meu ponto - de que, se você estiver lidando com um grande problema enum e você deve adicionar ou remover casos de tempos em tempos, sua solução é propensa a erros de omissão, enquanto a resposta atual, embora não seja concisa, é mais segura.No Swift 3, quando o enum subjacente tem
rawValue
, você poderá implementar oStrideable
protocolo. As vantagens são que nenhuma matriz de valores é criada, como em outras sugestões, e que o loop Swift "for in" padrão funciona, o que cria uma boa sintaxe.fonte
Esta solução atinge o equilíbrio certo de legibilidade e manutenção.
fonte
Desculpe, minha resposta foi específica de como eu usei este post no que eu precisava fazer. Para aqueles que se deparam com essa pergunta, procurando uma maneira de encontrar um caso dentro de uma enumeração, esta é a maneira de fazê-lo (novo em Swift 2):
Edit: lowercase camelCase agora é o padrão para os valores de enumeração do Swift 3
Para aqueles que se perguntam sobre a enumeração em uma enumeração, as respostas fornecidas nesta página que incluem uma var / let estática contendo uma matriz de todos os valores de enumeração estão corretas. O último exemplo de código da Apple para tvOS contém exatamente essa mesma técnica.
Dito isto, eles devem criar um mecanismo mais conveniente para o idioma (Apple, você está ouvindo?)!
fonte
O experimento foi: EXPERIMENT
Adicione um método ao cartão que crie um baralho completo, com um cartão de cada combinação de valor e naipe.
Portanto, sem modificar ou aprimorar o código fornecido, além de adicionar o método (e sem usar coisas que ainda não foram ensinadas), eu vim com esta solução:
fonte
Aqui está um método que eu uso para iterar
enum
e fornecer vários tipos de valores de umenum
Esta é a saída:
O número Zero em francês: zéro, espanhol: cero, japonês: nuru
O número um em francês: un, espanhol: uno, japonês: ichi
O número dois em francês: deux, espanhol: dos, japonês: ni
O número três em francês : trois, espanhol: tres, japonês: san
O número quatro em francês: quatre, espanhol: cuatro, japonês: shi
O número cinco em francês: cinq, espanhol: cinco, japonês: go
O número seis em francês: seis, espanhol: seis, japonês: roku
O número sete em francês: sept, espanhol: siete, japonês: shichi
Total de 8 casos
siete em japonês: shichi
ATUALIZAR
Eu criei recentemente um protocolo para lidar com a enumeração. O protocolo requer uma enumeração com um valor bruto Int:
fonte
Parece um hack, mas se você usar valores brutos, poderá fazer algo assim
fonte
Enquanto lida com
Swift 2.0
aqui é a minha sugestão:Eu adicionei o tipo bruto a
Suit
enum
então:
fonte
Tal como acontece com a @Kametrixom, responda aqui , acredito que retornar um array seria melhor do que retornar o AnySequence, já que você pode ter acesso a todos os presentes do Array, como count, etc.
Aqui está a reescrita:
fonte
Outra solução:
fonte
Este é um post bastante antigo, do Swift 2.0. Agora, existem algumas soluções melhores aqui que usam recursos mais recentes do swift 3.0: Iterando através de um Enum no Swift 3.0
E nesta questão há uma solução que usa um novo recurso (o ainda não lançado, enquanto escrevo esta edição) Swift 4.2: Como obtenho a contagem de uma enumeração Swift?
Existem muitas boas soluções nesse segmento e outras, no entanto, algumas delas são muito complicadas. Eu gosto de simplificar o máximo possível. Aqui está uma solução que pode ou não funcionar para diferentes necessidades, mas acho que funciona bem na maioria dos casos:
Para iterar:
fonte
Enums têm
toRaw()
efromRaw()
métodos. Portanto, se seu valor bruto for umInt
, é possível iterar do primeiro ao últimoenum
:Uma dica é que você precisa testar valores opcionais antes de executar o
simpleDescription
método, portanto, definimosconvertedSuit
nosso valor primeiro e, em seguida, definimos uma constante comoconvertedSuit.simpleDescription()
fonte
Aqui está minha abordagem sugerida. Não é completamente satisfatório (eu sou muito novo no Swift e OOP!), Mas talvez alguém possa refinar isso. A idéia é fazer com que cada enum forneça suas próprias informações de intervalo como
.first
e.last
propriedades. Ele adiciona apenas duas linhas de código a cada enumeração: ainda um pouco codificado, mas pelo menos não está duplicando todo o conjunto. Requer a modificação doSuit
enum para ser um Int como oRank
enum, em vez de não digitado.Em vez de ecoar a solução inteira, eis o código que adicionei à
.
enum, em algum lugar após as instruções de caso (aSuit
enum é semelhante):e o loop que eu usei para construir o baralho como uma matriz de String. (A definição do problema não indicava como o baralho deveria ser estruturado.)
Não é satisfatório porque as propriedades estão associadas a um elemento e não à enumeração. Mas isso adiciona clareza aos loops 'for'. Eu gostaria de dizer em
Rank.first
vez deRank.Ace.first
. Funciona (com qualquer elemento), mas é feio. Alguém pode mostrar como elevar isso ao nível de enum?E para fazê-lo funcionar, tirei o
createDeck
método da estrutura do cartão. Eu não conseguia descobrir como obter uma matriz [String] retornada dessa estrutura, e isso parece um lugar ruim para colocar esse método de qualquer maneira.fonte
Eu fiz isso usando a propriedade computada, que retorna a matriz de todos os valores (graças a este post http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). No entanto, ele também usa int raw-values, mas não preciso repetir todos os membros da enumeração em propriedades separadas.
ATUALIZAÇÃO O Xcode 6.1 mudou um pouco a maneira de obter o membro enum usando
rawValue
, então eu consertei a listagem. Também foi corrigido um pequeno erro com o erro errado primeirorawValue
.fonte
Baseado na resposta de Rick: isso é 5 vezes mais rápido
fonte
Count
caso quebraráswitch
implementações eCaseIterable
conformidade exaustivas .