2010-06-22 12 views
17

Czy ktoś wie, czy coś takiego jest możliwe w Scala:Czy jest możliwe, opcjonalny argument wartość zależy od innego argumentu w Scala

case class Thing(property:String) 

def f(thing:Thing, prop:String = thing.property) = println(prop) 

Powyższy kod nie kompiluje; dając błąd error: not found: value thing na thing.property

Poniżej przedstawiono oczekiwane zachowanie:

f(Thing("abc"), "123") // prints "123" 
f(Thing("abc"))  // prints "abc" 

ja zrealizować mogę dokonać prop argumentu Option[String] i wykonać kontrolę w definicji funkcji, ale zastanawiałem się, czy nie było sposób obejścia go z nowym nazwanym/domyślnym wsparciem argumentów w 2.8.0.

Odpowiedz

20

Tak, jest to możliwe w Scala 2.8. Oto cytat z dokumentu "Named and Default Arguments in Scala 2.8" design:

Ponieważ zakres parametru rozciąga nad wszystkimi listami kolejnych parametrów (i ciele metody), domyślne wyrażenia może zależeć od parametrów z poprzednich list parametrów (ale nie dla innych parametrów na tej samej liście parametrów ). Zauważ, że gdy używasz domyślnych wartości, które zależą od wcześniejszych parametrów , używane są rzeczywiste argumenty , a nie domyślne argumenty .

def f(a: Int = 0)(b: Int = a + 1) = b // OK 

I kolejny przykład:

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 

Zgodnie z tym, Twój kod może wyglądać następująco:

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 
+0

Dzięki, to jest dokładnie to, czego szukałem. –

+0

Nie ma za co :) –

0

To jest dokładnie to, do czego służy Option. Możesz użyć metody getOrElse przed wywołaniem metody lub wewnątrz metody 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 

Oh tutaj jest coś można zrobić za pomocą domyślnych argumentów:

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 

Oczekiwane zachowanie można osiągnąć za pomocą prostego przeciążeniem. Musiałem położyć metodę w object ponieważ wygląda REPL nie pozwala na bezpośrednie deklaracje funkcji przeciążonych:

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 
+0

Ale myślę, że niewłaściwą praktyką jest zmuszanie się do podawania "Opcji" zamiast zwykłych argumentów. –

1

Innym prostym rozwiązaniem jest po prostu przeciążać metody:

case class Thing (property: String) 

def f(thing: Thing, prop: String) = println(prop) 

def f(thing: Thing) = f(thing, thing.property) 
+0

Jeśli się nie mylę, to w jaki sposób C++ definiuje parametry opcjonalne/domyślne, prawda? –

+0

Długo programowałem w C++, ale możesz zrobić to samo w C++ lub w Javie. – Jesper

Powiązane problemy