2015-04-09 4 views
4

Во многих случаях я использую параметры в виде Option с None по умолчанию - как это:Автоматически обернуть параметры Параметры

def foo(bar:Option[String] = None) 

Это становится удобно и позволяет мне легко опускать null с. Однако, если я это сделаю, мне нужно изменить каждый вызов метода в

foo(Some("bar")) 

вместо того, чтобы просто

foo("bar") 

Это, однако, выглядит немного излишним, так как очевидно, что, когда Я указываю, что это полный вариант. Я почти уверен, что могу попытаться написать некоторые неявные конвертеры для такой упаковки для меня - к сожалению, я понятия не имею, как это сделать.

Бонус - это нормальная вещь? Есть ли другой способ решения проблемы «нулевых» параметров?

ответ

6

Я дам вам несколько вариантов (каламбур).


Не используйте необязательный параметр, и вместо этого использовать Option.apply. Это полезно, когда параметр необязательно является необязательным, но вы хотите иметь дело с возможными передаваемыми значениями null.

def foo(bar: String): ?? = Option(bar)... // operate on the Option[String] 

Преимущество этого в том, что Option.apply автоматически преобразует null в None для вас, так что нет абсолютно никакой необходимости в использовании, если/другое.


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

def foo(bar: String): ?? = foo(Option(bar)) 

def foo(bar: Option[String]): ?? = ??? 

Пример:

def foo(bar: String): Option[String] = foo(Option(bar)) 

def foo(bar: Option[String]): Option[String] = bar.map(_ + "aaa") 

scala> foo("bbb") 
res7: Option[String] = Some(bbbaaa) 

scala> foo(null: String) // The String ascription is necessary here. 
res9: Option[String] = None 

scala> val str: String = null 
scala> foo(str) // No ascription necessary, since we know the type. 
res10: Option[String] = None 

Косвенно преобразовать все, чтобы Option.

implicit def any2Opt[A](value: A): Option[A] = Option(value) 

И сохранить текущий definintion из

def foo(bar: Option[String]): ?? = ??? 

Косвенно превращающего в Option, однако, может привести к некоторым неожиданным результатам, так что будьте осторожны.

0

вы можете определить неявное преобразователь, как:

implicit def conv(str: String): Option[String] = { 
     if (str == null) None else Some(str) 
    } 

    def foo(bar: Option[String] = None) = { 
     bar 
    } 

Выход:

scala> foo("xyz") 
res55: Option[String] = Some(xyz) 
scala> foo() 
res1: Option[String] = None 
+2

Опция (null) равна None. – mohit

1

Вы можете написать нужный общий неявный, как

implicit def wrapToOption[T](x: T) = Option[T](x) 

Тогда вы можете сделать

def foo(bar: Option[String] = None) = println(bar) 
foo("bar") //> Some(bar) 
foo()  //> None 

def fooBar(bar: Option[Int] = None) = println(bar) 
fooBar(2) //> Some(2) 

Об этом, будучи здравомыслящей вещи, я скажу нет (личное мнение). Implicits, как правило, трудно отлаживать. Логика, которая пошла не так, подразумевает, может превратить вашу жизнь в ад.

Кроме того, каждое новое дополнение к команде должно будет преподать обо всех этих «волшебствах», происходящих за кулисами.

+0

WoW! Оно работает! Тем не менее, вы правы в отношении этих «волшебных» я все равно должен добавить этот неявный (или импорт) в каждый файл, который я использую. – M4ks

+0

@ M4ks, если вас беспокоит «магия», см. Мой ответ ниже, который предлагает способ смягчить это. – vptheron

+0

Я думаю, что ответы @ m-z немного лучше, поскольку он представляет не магическое решение, извините за «неприемлемость», – M4ks

1

Это совершенно разумный подход, чтобы установить тип ваших параметров на Option[_], если они действительно могут быть дополнительными. Однако я не рекомендую использовать implicits для прямого преобразования в Option[_].

Вы можете сделать синтаксис немного легче на глаз, в том числе Scalaz и использование some:

foo("hello".some) 

Если вы не хотите, чтобы принести в Scalaz только для этого очень легко написать свой собственный неявный для этого. Это подразумевается лучше, потому что вы явно вызываете метод some для «запуска» неявного, а не «магического» преобразования.

Другой вариант, если вы часто вызываете функцию с параметрами, установленными в Some[_] является перегружать его (опять же, я не поклонник перегрузки либо):

def foo(x: Option[String] = None, y: Option[Int] = None, z: Option[String] = None) { /* do stuff */ } 

def foo(x: String, y: Int, z: Option[String] = None) = foo(x.some, y.some, z) 

На заключительной ноте, я дон Не думаю, что что-то не так с обертыванием ваших аргументов в Some, если функция четко определяет их как необязательные. Я бы не стал беспокоиться об этом синтаксисе.

0

Непосредственное преобразование всего в Option - опасная игра, которую я бы избегал! Вы можете предпочесть просто иметь некоторый метод перегрузкам:

object Foos { 
    private def foo(bar: Option[String]): Unit = println(bar.getOrElse("foobar")) 
    def foo(bar: String): Unit = foo(Some(bar)) 
    def foo(): Unit = foo(None) 
} 

И тогда вы можете сделать:

Foos.foo("barfoo") //prints "barfoo" 
Foos.foo() //prints "foobar" 

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

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