2017-10-18 102 views
1

我想創建一個函數與下面的簽名元組:轉換由名稱參數

def myFunction[T](functionWithName: (String, => T)): T 

,這樣我可以調用它,例如,像這樣:val x = myFunction("abc" -> 4 * 3)。但是,Tuple不接受名稱參數,所以上面的簽名是無效的。

通過this answer的啓發,我想下面的隱式轉換:

implicit class ByName[T](getValue: => T) extends Proxy { 
    def apply(): T = getValue 
    def self = apply() 
} 

def myFunction[T](functionWithName: (String, ByName[T])): T = { 
    // do something 
    functionWithName._2() 
} 

隱含不會在這種情況下工作,但是(不像在鏈接的答案)。

  • 爲什麼隱式轉換爲ByName不起作用?
  • 如何才能達到myFunction("abc" -> 4 * 3)的名稱所要傳遞4 * 3的預期效果?
+1

爲什麼一個元組,什麼是錯的2個參數? –

+1

@ insan-e實際上會有myFunction的多種變體。它可以稱爲'myFun(「a」 - > 1 * 2,「b」 - > 3 * 4)「或myFun(」a「 - > 1 * 2,」b「 - > 3 * 4」 c「 - > 5 * 6)'等等。因爲可能有很多參數,所以我想避免任何不必要的語法來保持它的可讀性。 – Mifeet

+1

我明白了。你不能這樣做,可能是因爲[元組](https://github.com/scala/scala/blob/v2.12.3/src/library/scala/Tuple2.scala#L19)有熱烈的爭論。我看到的唯一方法是按名稱創建整個元組,'functionWithName:=>(String,T)'... –

回答

1

我有兩個建議,以實現這一點:

  • 製作整個元組通過名字:functionWithName: => (String, T)

  • 使自己的等級:

    class MyTuple[A, B](a: A, b: => B) { 
        def _1: A = a 
        def _2: B = b 
        def toTuple = a -> b // optional 
    } 
    

,並有一個自定義的隱式方法的地方,像->用於Tuple2(見ArrowAssocPredef):

implicit final class ArrAssoc[A](private val self: A) extends AnyVal { 
    @inline def -->[B](y: => B): MyTuple[A, B] = { 
     new MyTuple(self, y) 
    } 
    } 

然後,你可以這樣說:

val t = 1 --> { println("blah"); 5 } 
    //t._2 
    //t.toTuple 

The b para儀表不應該被評估,直到調用t._2 甚至使toTuple imlicit轉換,所以當Tuple2被espected你可以傳遞一個MyTuple ...

4

您可以將call-by-name參數更改爲thunk。

def myFunction[T](functionWithName: (String,() => T)): T = functionWithName._2() 

myFunction(("abc",() => 4 * 3)) // 12 

,或者把它與implicit工作,你只需要明確提供類型myFunction

myFunction[Int]("abc" -> 4 * 3) // 12 
+0

是的,那是另一種選擇。但是,如果沒有不必要的2個括號和箭頭運算符,怎麼辦?任何想法爲什麼隱式轉換不起作用? – Mifeet

+0

@Mifeet查看我更新的答案。如果你提供這個類型,'implicit'就起作用。 – adrice727