2015-08-11 10 views
9

Quindi sto cercando di estendere i tipi di interi di Swift con alcune funzioni utili che uso molto, tuttavia non sono chiaro su quali protocolli dovrei estendere.Estensione di tipi di numeri interi generici in Swift

Ad esempio, supponiamo di voler implementare una funzione per il blocco di un valore (se è inferiore al minimo impostarlo, altrimenti se è maggiore di un valore massimo, impostarlo su quello). Il mio primo pensiero è stato quello di fare qualcosa di simile:

extension Int { 
    func clamp(minimum:Int, maximum:Int) { 
     if self < minimum { return minimum } 
     if self > maximum { return maximum } 
     return self 
    } 
} 

po 'di un esempio semplicistico, ma illustra il problema; se ora voglio chiamare questo per un UInt quindi naturalmente non posso, quindi devo aggiungere un equivalente a UInt, ma che non funzionerà per un UInt16 e così via.

Ho pensato che potrei forse estendere qualcosa più in alto sulla catena e utilizzare invece i generici, tuttavia non è possibile estendere protocolli come IntegerType.

Quindi, c'è un posto più appropriato che potrei inserire la mia estensione (s)?

+1

Anziché estendere un tipo con cui tutti hanno già familiarità, dovresti racchiudere l'Integer con la tua classe o inserire i tuoi metodi usati frequentemente in una classe util matematica statica – bhspencer

+2

Non è un'estensione inteso in modo ecologico come alternativa a questo? Ho pensato che potevo semplicemente inserire le mie funzioni in un'estensione di dire 'IntegerType' usando i generici e in questo modo apparirebbe per tutti i valori interi. Mi sembra molto più ordinato di una classe IntUtils con un sacco di funzioni statiche. – Haravikk

+1

L'argomento per non farlo è che esiste un'interfaccia ben nota per i tipi di basso livello che tutti i programmatori di una particolare lingua conosceranno. Se so cosa si può fare con un intero in un progetto, dovrei sapere cosa si può fare con un intero in un altro progetto. – bhspencer

risposta

7

Per Swift 2, vedere la risposta di Andriy Gordiychuk, che sarà corretto allora. Se hai bisogno di Swift 1, questo non può essere fatto con le estensioni e deve essere eseguito con funzioni gratuite. Questo è il motivo per cui ci sono così tante funzioni gratuiti a stdlib che divennero le estensioni a Swift 2.

Per Swift 1, quello che dovete fare è:

func clamp<T:Comparable>(value: T, #minimum:T, #maximum:T) -> T { 
    if value < minimum { return minimum } 
    if value > maximum { return maximum } 
    return value 
} 

Se si preferisce modificare il valore (come l'esempio di Andriy fa), puoi farlo in questo modo:

func clamp<T:Comparable>(inout value: T, #minimum:T, #maximum:T) { 
    if value < minimum { value = minimum } 
    else if value > maximum { value = maximum } 
} 

Altrimenti devi scrivere un'estensione su ogni tipo. È l'unica altra risposta in Swift 1. Swift 2 è molto meglio.

+0

Sembra che questa sia la risposta corretta per ora; fortunatamente non sono pressato per il tempo, quindi posso solo arrangiarlo per ora e rivisitarlo quando arriva Swift 2, grazie per la risposta! – Haravikk

1

Sei sulla strada giusta. Infatti stai parlando di Protocol Oriented Programming.

estensioni Protocollo: Swift è molto concentrato sul protocollo orientato alla sviluppo - c'è anche una sessione sul tema al WWDC 2015. Swift 2.0 aggiunge estensioni di protocollo, e la libreria standard stesso li usa ampiamente. Dove hai utilizzato le funzioni globali, Swift 2.0 ora aggiunge metodi a tipi comuni, quindi le funzioni funzionano in modo naturale e il codice è molto più leggibile.

https://developer.apple.com/swift/blog/?id=29

infatti una grande caratteristica di Swift 2.0 è che permette di aggiungere i metodi per i protocolli in modo da poter aggiungere clamp-IntegerType.

Il video spiega molto bene il tema della Protocol Oriented Programming: https://developer.apple.com/videos/wwdc/2015/?id=408

Hai solo bisogno di eseguire l'aggiornamento a Swift 2.0.

4

Mentre Swift 2.0 è ancora in versione beta, suggerisco di aggiungere estensioni come quelle illustrate. Dovrai copiare e incollare lo stesso codice per Int, Int64 ecc., Ma non c'è altro modo di fare ciò che vuoi al momento.

volta Swift 2.0 è fuori si sarà in grado di fare questo

extension IntegerType { 
    mutating func clamp(minimum:Self, maximum:Self) { 
     if self < minimum { self = minimum } 
     if self > maximum { self = maximum } 
    } 
} 

Se si può aspettare con il rilascio della vostra applicazione fino a qualche tempo nel mese di settembre, allora vi incoraggio a iniziare a utilizzare Swift 2.0 al momento.

Aggiornamento

Con Swift 2.0 è anche possibile aggiungere un'estensione al protocollo Comparable che farà sì che clamp() è disponibile per altri tipi come Double, Float, ecc

extension Comparable { 
    mutating func clamp(minimum:Self, maximum:Self) { 
     if self < minimum { self = minimum } 
     if self > maximum { self = maximum } 
    } 
} 
+0

Si noti che per l'esempio dato, dove 'clamp' restituisce un valore anziché mutare, questo è meglio applicato a' Comparable' piuttosto che 'IntegerType'. –

+0

Questo è vero, ma la funzione originale non ha dichiarato il tipo restituito (sebbene contenesse "return" nel suo corpo). Quindi, ho assunto che 1) @Haravikk volesse estendere solo il tipo intero (che sembra il caso) e 2) che è più facile, a questo scopo, usare a.clamp() piuttosto che a = a.clamp() –

+0

On Il secondo pensiero, indipendentemente dal fatto che ritorni o meno, non ha importanza. Può essere ancora comparabile anche nella tua versione. –

1
extension Comparable { 
    func clamp(var minimum: Self, var _ maximum: Self) -> Self { 
     if maximum < minimum { swap(&maximum, &minimum) } 
     if self < minimum { return minimum } 
     if self > maximum { return maximum } 
     return self 
    } 
} 
1

A titolo di esempio, qui è un'implementazione intero di clamped che si applica anche genericamente a tutto ciò che può utilizzare:

extension Comparable 
{ 
    func clamped(from lowerBound: Self, to upperBound: Self) -> Self { 
     return min(max(self, lowerBound), upperBound) 
    } 

    func clamped(to range: ClosedRange<Self>) -> Self { 
     return min(max(self, range.lowerBound), range.upperBound) 
    } 
} 

extension Strideable where Self.Stride: SignedInteger 
{ 
    func clamped(to range: CountableClosedRange<Self>) -> Self { 
     return min(max(self, range.lowerBound), range.upperBound) 
    } 
} 

E i test:

7.clamped(from: 3, to: 6) // 6 

7.clamped(to: 3 ... 6)  // 6 
7.clamped(to: 3 ... 7)  // 7 
7.clamped(to: 3 ... 8)  // 7 

7.0.clamped(to: 3.0 ... 6.0) // 6 
7.0.clamped(to: 3.0 ... 7.0) // 7 
7.0.clamped(to: 3.0 ... 8.0) // 7