Então, por exemplo, este código:
func trigramSimilarity(to other: Set<String>) -> Double {
let selfTrigram = trigrams()
let total = selfTrigram.union(other)
let common = selfTrigram.intersection(other)
return total.isEmpty ? 0 : Double(common.count) / Double(total.count)
}
Espero que o compilador se transforme em
func trigramSimilarity(to other: Set<String>) -> Double {
let selfTrigram = trigrams()
let total = selfTrigram.union(other)
return total.isEmpty ? 0 : Double(selfTrigram.intersection(other).count) / Double(total.count)
}
Percebendo que let common
não é necessário que total.isEmpty
o compilador Swift me permita escrever código mais simples, mas evite cálculos desnecessários.
Mas é mais seguro ser simplesmente explícito?
Como você pode ver na saída do Godbolt que o Sweeper vinculou,
Set.intersection(_:)
ele é chamado incondicionalmente, o que é potencialmente um desperdício setotal.isEmpty
for verdade.Seu código pede para
Set.intersection(_:)
ser chamado incondicionalmente, então o compilador é obrigado a produzir código que se comporte como se ele realmente tivesse sido chamado. A maneira óbvia de fazer isso é chamá-lo. Mas ele também pode ser esperto e pular a chamada, mas somente se puder ter certeza de que funções não têm efeitos colaterais observáveis. Isto é, se não houver como observar se ele foi chamado ou não. A menos que ele possa provar isso, ele tem que ser conservador e deixar a chamada.Neste caso, acho que é mais claro usar um
if
/ explícitoelse
de qualquer maneira:A saída compilada confirma que
common
agora só é computada setotal.isEmpty
for falso.Melhor ainda, sugiro usar um retorno antecipado: