2015-11-06 3 views
6

Поэтому у меня есть несколько перечислений, представляющих различные системы единиц:Swift расширения протокола с перечислениями

enum MassUnit:Double{ 
    case Pound = 453.59237, Ounce = 28.349523125, Gram = 1.0, Kilogram = 1000.0; 
} 
enum VolumeUnit:Double{ 
    case Teaspoon = 1, Tablespoon = 3, Cup = 48, Pint = 96, Quart = 192, Gallon = 768, Liter = 202.884136211, Milliliter = 0.202884136211 
} 
enum TimeUnit:Double{ 
    case Second = 1, Minute = 60, Hour = 3600, Day = 86400, Week = 604800, Year = 31536000 
} 

То, что я хотел бы сделать, это иметь возможность конвертировать из одной единицы в другую, например, из года в секунды. Для этого я убедился, что исходные значения для моих перечислений соответствуют коэффициентам преобразования, например 1 мин = 60 секунд. Таким образом, при й количестве некоторой единицы, преобразование просто

x * rawValue1/rawValue2 // rawValue2 = rawValue of desired unit. 

Хотя это преобразование достаточно просто, я хотел бы, чтобы быть эффективными и использовать протокол:

protocol Convertable{ 
    func convert(inputAmount inputAmount:Double, outputUnit:Self)->Double; 
} 

Тогда я мог бы расширить перечисление:

extension TimeUnit:Convertable{ 
    func convert(inputAmount inputAmount: Double, outputUnit: TimeUnit) -> Double { 
     return inputAmount * self.rawValue/outputUnit.rawValue; 
    } 
} 

Тогда я мог бы просто преобразовать так:

TimeUnit.Year.convert(inputAmount: 2.54, outputUnit: .Second) 
// returns 80101440 

Это здорово, однако, в зависимости от того, сколько единиц я хочу преобразовать, было бы много дублирования одного и того же кода.

Итак, что бы я хотел сделать, так или иначе использовать расширение протокола.

extension Convertable{ 
    func convert(inputAmount inputAmount: Double, outputUnit: Self) -> Double { 
     return inputAmount * self.rawValue/outputUnit.rawValue;// Compile error... 
    } 
} 

Это где я попадаю в неприятности, выходной блок объявлен как самости, которая ничего не знает о RawValue.

Любые идеи?

ответ

7

Права, когда я задавал этот вопрос, ответ пришел ко мне: Есть конвертируемый протокол также требуют переменной RawValue:

protocol Convertable{ 
    var rawValue:Double{get} 
    func convert(inputAmount inputAmount:Double, outputUnit:Self)->Double; 
} 

Таким образом, ссылки self.rawValue известно, и так перечислений уже есть RawValue , не требуется дополнительная работа:

enum MassUnit:Double, Convertable{ 
    case Pound = 453.59237, Ounce = 28.349523125, Gram = 1.0, Kilogram = 1000.0; 
} 

enum VolumeUnit:Double, Convertable{ 
    case Teaspoon = 1, Tablespoon = 3, Cup = 48, Pint = 96, Quart = 192, Gallon = 768, Liter = 202.884136211, Milliliter = 0.202884136211 
} 

enum TimeUnit:Double, Convertable{ 
    case Second = 1, Minute = 60, Hour = 3600, Day = 86400, Week = 604800, Year = 31536000 
} 

А затем с помощью конвертера:

TimeUnit.Year.convert(inputAmount: 2.54, outputUnit: .Second) // 80101440 
MassUnit.Gram.convert(inputAmount: 20.0, outputUnit: .Ounce) //0.70547 
VolumeUnit.Pint.convert(inputAmount: 0.2, outputUnit: .Tablespoon)// 6.4000 

Даже Бетер, в нечетном случае, когда преобразование не работает, как это, я могу переопределить функцию преобразования с моей собственной реализацией, например, в Temperature:

enum TemperatureUnit:Double, Convertable{ 
    case Celsius, Fahrenheit 

    func convert(inputAmount inputAmount: Double, outputUnit: TemperatureUnit) -> Double { 
     if self == outputUnit { 
      return inputAmount; 
     } else if self == .Celsius { 
      return inputAmount * 9.0/5.0 + 32.0 
     } else { 
      return (inputAmount - 32.0) * 5.0/9.0; 
     } 
    } 
} 

TemperatureUnit.Celsius.convert(inputAmount: 3, outputUnit: .Fahrenheit) // 37.4 
TemperatureUnit.Fahrenheit.convert(inputAmount: 0, outputUnit: .Celsius) // -17.7778 

Красивый!

+1

Почему бы просто не превратить «Конвертируемый» в соответствие с «RawRepresentable»? то есть «протокол кабриолет: RawRepresentable» – jjatie

Смежные вопросы