Qual protocolo deve ser adotado por um Type para uma function genérica para pegar qualquer tipo de número como argumento no Swift?

Eu quero fazer uma function aceitar qualquer número (Int, Float, Double, …) em Swift

func myFunction  (number : T) -> { //... } 

sem usar NSNumber

Atualização: A resposta abaixo ainda se aplica em princípio, mas o Swift 4 completou um redesenho dos protocolos numéricos, de modo que adicionar o seu próprio é frequentemente desnecessário. Dê uma olhada nos protocolos numéricos da biblioteca padrão antes de construir seu próprio sistema.


Isso realmente não é possível fora da checkbox no Swift. Para fazer isso, você precisará criar um novo protocolo, declarado com quaisquer methods e operadores que você usar dentro de sua function genérica. Esse processo funcionará para você, mas os detalhes exatos dependerão um pouco do que sua function genérica faz. Veja como você faria isso para uma function que obtém um número n e retorna (n - 1)^2 .

Primeiro, defina seu protocolo, com os operadores e um inicializador que leva um Int (para que possamos subtrair um).

 protocol NumericType { func +(lhs: Self, rhs: Self) -> Self func -(lhs: Self, rhs: Self) -> Self func *(lhs: Self, rhs: Self) -> Self func /(lhs: Self, rhs: Self) -> Self func %(lhs: Self, rhs: Self) -> Self init(_ v: Int) } 

Todos os tipos numéricos já implementam estes , mas neste momento o compilador não sabe que eles estão em conformidade com o novo protocolo NumericType . Você tem que tornar isso explícito – a Apple chama isso de “declarar adoção de protocolo com uma extensão”. Faremos isso para Double , Float e todos os tipos inteiros:

 extension Double : NumericType { } extension Float : NumericType { } extension Int : NumericType { } extension Int8 : NumericType { } extension Int16 : NumericType { } extension Int32 : NumericType { } extension Int64 : NumericType { } extension UInt : NumericType { } extension UInt8 : NumericType { } extension UInt16 : NumericType { } extension UInt32 : NumericType { } extension UInt64 : NumericType { } 

Agora podemos escrever nossa function real, usando o protocolo NumericType como uma restrição genérica.

 func minusOneSquared (number : T) -> T { let minusOne = number - T(1) return minusOne * minusOne } minusOneSquared(5) // 16 minusOneSquared(2.3) // 1.69 minusOneSquared(2 as UInt64) // 1 

Como esclarecimento relacionado ao comentário, e para aqueles que não conhecem muito bem os protocolos do Swift, o ponto aqui é que os methods declarados no tipo numérico já estão implementados por cada um dos tipos para os quais a conformidade foi declarada. Por exemplo, porque o tipo Int já implementa …

 func +(lhs: Self, rhs: Self) -> Self 

… nenhum outro detalhe de implementação é necessário no protocolo NumericType.

O propósito da declaração do protocolo neste caso não é adicionar novos methods a qualquer um dos seus tipos de implementação, mas fornecer uma fachada unificada que permita ao compilador saber que qualquer coisa que implemente o NumericType suporta o conjunto completo de operadores matemáticos do Swift. Como cada um dos tipos que tiveram a compatibilidade NumericType adicionada a eles já implementa todos os methods em NumericType, tudo o que é necessário para que eles estejam em total conformidade com o protocolo é declarar que eles estão em conformidade …

 extension Int : NumericType { }