Возможно ли, чтобы значение необязательного аргумента зависело от другого аргумента в Scala
Кто-нибудь знает, возможно ли что-то подобное в Scala:
case class Thing(property:String)
def f(thing:Thing, prop:String = thing.property) = println(prop)
Вышеприведенный код не компилируется; давая ошибку error: not found: value thing
при thing.property
Ниже показано ожидаемое поведение:
f(Thing("abc"), "123") // prints "123"
f(Thing("abc")) // prints "abc"
Я понимаю, что могу сделать аргумент prop
a Option[String]
и выполнить проверку в определении функции, но мне было интересно, существует ли способ вокруг него с новой поддержкой аргументов named/default в 2.8.0.
Ответы
Ответ 1
Да, это возможно в Scala 2.8. Здесь приведена цитата из "Именованные аргументы и аргументы по умолчанию в Scala 2.8" :
Поскольку область действия параметра продолжается по всем последующим спискам параметров (и тело метода), по умолчанию выражения могут зависеть от параметров предыдущих списков параметров (но не по другим параметрам в том же список параметров). Обратите внимание, что при использовании значение по умолчанию, которое зависит от более ранние параметры, фактические используются аргументы, а не по умолчанию Аргументы.
def f(a: Int = 0)(b: Int = a + 1) = b // OK
И еще один пример:
def f[T](a: Int = 1)(b: T = a + 1)(c: T = b)
// generates:
// def f$default$1[T]: Int = 1
// def f$default$2[T](a: Int): Int = a + 1
// def f$default$3[T](a: Int)(b: T): T = b
В соответствии с этим ваш код может выглядеть следующим образом:
scala> case class Thing(property:String)
defined class Thing
scala> def f(thing:Thing)(prop:String = thing.property) = println(prop)
f: (thing: Thing)(prop: String)Unit
scala> f(Thing("abc"))("123")
123
scala> f(Thing("abc"))()
abc
Ответ 2
Еще одно простое решение - просто перегрузить метод:
case class Thing (property: String)
def f(thing: Thing, prop: String) = println(prop)
def f(thing: Thing) = f(thing, thing.property)
Ответ 3
Это именно то, для чего Option
. Вы можете использовать метод getOrElse
перед вызовом метода или внутри метода f
.
scala> val abc = Some("abc")
abc: Some[java.lang.String] = Some(abc)
scala> val none: Option[String] = None
none: Option[String] = None
scala> println(abc getOrElse "123")
abc
scala> println(none getOrElse "123")
123
scala> def f(o: Option[String]) = println(o getOrElse "123")
f: (o: Option[String])Unit
scala> f(abc)
abc
scala> f(none)
123
О, вот что вы можете сделать с помощью аргументов по умолчанию:
scala> case class Thing(property: String = "123")
defined class Thing
scala> def f(t: Thing) = println(t.property)
f: (t: Thing)Unit
scala> f(Thing("abc"))
abc
scala> f(Thing())
123
Ожидаемое поведение может быть достигнуто при простой перегрузке. Мне нужно было поместить метод в object
, потому что похоже, что REPL не разрешает прямые перегруженные объявления функций:
scala> object O {
def overloaded(t:Thing) = println(t.property)
def overloaded(t:Thing,s:String) = println(s)
}
defined module O
scala> O.overloaded(Thing("abc"), "123")
123
scala> O.overloaded(Thing("abc"))
abc