Um guia de estilo e convenções de programação para projetos em Swift
Esta é uma tentativa de incentivar padrões para alcançar os seguintes objetivos (mais ou menos em ordem de prioridade):
- Maior rigor e diminuição da probabilidade de erro do programador
- Aumento da clareza de intenção
- Verbosidade reduzida
- Menos debates sobre estética
Se você tiver sugestões, por favor, consulte as nossas [orientações de contribuição] (CONTRIBUTING.md), em seguida, abra uma pull request. ⚡
- Tabs, não espaços.
- Termine arquivos com novas linhas.
- Use espaços em branco verticais à vontade para dividir o código em blocos lógicos.
- Não deixe espaços em branco no final das linhas
- Nem mesmo indentação em linhas em branco.
Use let foo = ...
ao invés de var foo = ...
sempre que possível (e em caso de dúvida). Só use var
se for absolutamente necessário (isto é, você sabe que o valor pode mudar, por exemplo, quando se utiliza o modificador de armazenamento weak
).
Justificativa: A intenção e o significado de ambas palavras-chave são claros, mas let-como-padrão resulta em código mais seguro e mais claro.
Um let
-binding garante e sinaliza claramente para o programador que seu valor nunca vai mudar. Código subseqüente pode assim fazer suposições mais fortes sobre seu uso.
Torna-se mais fácil raciocinar sobre o código. Se você tivesse usado var
enquanto supondo que o valor nunca muda, teria que verificar manualmente isso.
Assim, sempre que você vir um identificador var
sendo usado, suponha que ele vai mudar e se pergunte o porquê.
Quando você tem que atender a certos critérios para continuar a execução, tente sair o mais cedo possível. Assim, em vez disto:
if n.isNumber {
// Use n aqui
} else {
return
}
use isto:
guard n.isNumber else {
return
}
// Use n aqui
Você também pode fazer isso com uma declaração if
, mas é preferível usar guard
porque uma declaração guard
sem return
, break
ou continue
produz um erro de compilação. Logo, a saída é garantida.
Se você tem um identificador foo
do tipo FooType?
ou FooType!
, se possível não use unwrapping forçado para chegar ao valor subjacente (foo!
). Em vez de forçar, é preferível:
if let foo = foo {
// Use o valor de `foo` unwrapped aqui
} else {
// Se necessário, tratar o caso em que o opcional é nil
}
Alternativamente, você pode querer usar encadeamento de opcionais em alguns desses casos, por exemplo:
// Chamar a função se `foo` não é nil. Se `foo` é nil, ignorar que já tentou fazer a chamada
foo?.callSomethingIfFooIsNotNil ()
Justificativa: Uso explícito de if let
-binding para opcionais resulta em código mais seguro. Unwrapping forçado é mais propenso a causar erros em tempo de execução.
Sempre que possível, use let foo: FooType?
ao invés de let foo:FooType!
se foo
pode ser nil
(Note-se que, em geral, ?
pode ser usado ao invés de !
).
Justificativa: Opcionais explícitos resultam em código mais seguro. Opcionais unwrapped implicitamente têm o potencial de produzir erros em tempo de execução.
Quando possível, omita a palavra-chave get
em propriedades somente-leitura computadas automaticamente e subscripts somente leitura.
Então, escreva assim:
var myGreatProperty: Int {
return 4
}
subscript(index: int) -> T {
return objects[index]
}
... e não assim:
var myGreatProperty: Int {
get {
return 4
}
}
subscript(index: int) -> T {
get {
return objects[index]
}
}
Justificativa: A intenção e o significado da primeira versão são claros e resultam em menos código.
Funções, tipos e variáveis de nível superior devem sempre ter especificadores de controle de acesso explícitos:
public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}
No entanto, as definições dentro destes podem deixar o controle de acesso implícito, onde apropriado:
internal struct TheFez {
var owner: Person = Joshaber()
}
Justificativa: É raro que definições de nível superior sejam especificamente internal
e ser explícito garante que essa decisão só é tomada de forma pensada. Dentro de uma definição, reutilizar o mesmo especificador de controle de acesso é duplicação de esforço e o padrão é geralmente razoável.
Ao especificar o tipo de um identificador, coloque sempre os dois pontos imediatamente após o identificador, seguido por um espaço e, em seguida, o nome do tipo.
classe SmallBatchSustainableFairtrade: Coffee {...}
let timeToCoffee: NSTimeInterval = 2
func makeCoffee (tipo: CoffeeType) -> Coffee {...}
Justificativa: O especificador de tipo diz algo sobre o identificador e deve ser posicionado junto a ele.
Além disso, ao especificar o tipo de um dicionário, sempre coloque os dois pontos imediatamente após o tipo da chave, seguido por um espaço e, em seguida, o tipo de valor.
let capitals: [Country: City] = [ Sweden: Stockholm ]
Ao acessar propriedades ou métodos em self
, deixe a referência ao self
implícita por padrão:
private class History {
var events: [Event]
func rewrite () {
events = []
}
}
Só inclua a palavra-chave explícita quando isso for requerido pela linguagem-por exemplo, em um closure ou quando há conflito com os nomes de parâmetros:
extension History {
init (events: [Event]) {
self.events = events
}
var whenVictorious: () -> () {
return {
self.rewrite ()
}
}
}
Justificativa: Isso faz com que a semântica de captura de self
se destaque mais em closures e evita a verbosidade em outros lugares.
A menos que você necessite de funcionalidade que só pode ser fornecida por uma classe (como identidade ou des-inicializadores), dê preferência a implementar um struct
.
Note-se que a herança (por si só) normalmente não é uma boa razão para usar as classes porque o polimorfismo pode ser fornecido por protocolos e reutilização de implementações pode ser fornecida através de composição.
Por exemplo, esta hierarquia de classes:
class Vehicle {
let numberOfWheels: Int
init (numberOfWheels: int) {
self.numberOfWheels = numberOfWheels
}
func maximumTotalTirePressure (pressurePerWheel: Float) -> Float {
return pressurePerWheel * float (numberOfWheels)
}
}
class Bycicle: Vehicle {
init() {
super.init(numberOfWheels: 2)
}
}
class Car: Vehicle {
init() {
super.init(numberOfWheels: 4)
}
}
poderia ser refatorada nestas definições:
protocol Vehicle {
var numberOfWheels: Int {get}
}
func maximumTotalTirePressure (vehicle: Vehicle, pressurePerWheel: Float) -> Float {
return pressurePerWheel * float (vehicle.numberOfWheels)
}
struct Bicycle: Vehicle {
let numberOfWheels = 2
}
struct Car: Vehicle {
let numberOfWheels = 4
}
Justificativa: Tipos de valor (ao invés de referência) são mais simples, mais fáceis de raciocinar sobre e se comportam conforme o esperado com a palavra-chave let
.
Classes devem começar como final
e só podem ser alteradas para permitir subclasses se uma necessidade válida para herança for identificada. Mesmo neste caso, tantas definições quanto possível dentro da classe devem ser final
, seguindo as mesmas regras.
Justificativa: A composição é geralmente preferível à herança e espera-se que a escolha de usar herança seja pensada com cuidado.
Métodos de tipos parametrizados podem omitir parâmetros de tipo no tipo de recepção quando eles são idênticos aos do receptor. Por exemplo:
struct Composite <T> {
...
func compose(other: Composite<T>) -> Composite<T> {
return Composite<T> (self, other)
}
}
poderia ser reescrita como:
struct Composite <T> {
...
func compose (other: Composite) -> Composite {
return Composite (self, other)
}
}
Justificativa: Omitir parâmetros de tipo redundantes clarifica a intenção e torna óbvio o caso contrário, quando o tipo retornado recebe parâmetros de diferentes tipos.
Use espaços em branco ao redor de operadores quando defini-los. Ao invés de:
func <|(lhs: Int, rhs: Int) -> Int
func <|<<A>(lhs: A, rhs: A) -> A
Escreva:
func <| (lhs: Int, rhs: Int) -> Int
func <|< <A>(lhs: A, rhs: A) -> A
Justificativa: Operadores consistem em caracteres de pontuação, o que pode torná-los difíceis de ler quando imediatamente seguidos pela pontuação para uma lista de parâmetros de tipo ou valor. Adicionar o espaço em branco separa os dois mais claramente.
- [中文 版] (https://github.com/Artwalk/swift-style-guide/blob/master/README_CN.md)
- [日本語 版] (https://github.com/jarinosuke/swift-style-guide/blob/master/README_JP.md)
- [한국어판] (https://github.com/minsOne/swift-style-guide/blob/master/README_KR.md)
- [Versión en Español] (https://github.com/antoniosejas/swift-style-guide/blob/spanish/README-ES.md)
- Versão original em Inglês