2012-02-14 75 views
3

我有以下情況:Scala的通用功能混亂

有一個方法def f(lst: List[Any]),這確實名單的一些改造和轉型(所有這些Any的是case類)的返回結果。我需要完成的是當輸入列表爲空時,生成一個列表,其中包含正確類型的一個元素並使用它進行轉換。

是否可以保證一個類型的水平,有些情況下類有一個無參數的構造函數?如果是這樣,Any應該被替換成什麼?如果不是,那麼完成這個的最好方法是什麼?也許我應該改變我的方法,如def f[T](lst: List[T], default: T)

任何幫助表示讚賞。

+3

注:'F'是一種方法,而不是一個函數。函數是用'=>'創建的(這基本上就是用於匿名擴展'FunctionN'特性之一和重載'apply'的語法糖),'def'定義了方法。 – 2012-02-14 16:07:17

+0

同意,謝謝澄清。 – folone 2012-02-15 08:26:50

回答

5

你在尋找類似的東西嗎?

import scalaz._ 
import Scalaz._ 

scala> def f[A : Zero](lst: List[A]) = { 
    | val xs = if(lst.isEmpty) List(mzero[A]) else lst 
    | xs ++ xs // some transformation 
    | } 
f: [A](lst: List[A])(implicit evidence$1: scalaz.Zero[A])List[A] 

scala> f(List.empty[Int]) 
res1: List[Int] = List(0, 0) 

scala> f(List("hello", "world")) 
res2: List[java.lang.String] = List(hello, world, hello, world) 

如果是的話,你可以參考this post我前段時間寫過這個主題。

+0

是的,謝謝。 – folone 2012-02-14 16:11:08

1

我不能完全確定你想做什麼(也許你可以包括一些細節),但有些意見,我可以馬上給的是,如果你有一堆相關的情況下類的,他們都應該延長一個密封的特質。這不僅可以讓您獲得更好的類型安全性(不再更多Any),但編譯器將能夠檢查詳盡的模式匹配。例如:

sealed trait Foo 
case class Bar(x: Int) extends Foo 
case class Baz(y: String) extends Foo 

然後,你可以定義你的函數,像這樣

def f[T <: Foo](lst: List[Foo], default: T)//... 

這將使list包含任何情況下類項目,但要求default是由類型指定的類型參數(它必須是Foo的子類型)

2

簡單的答案是否定的,類型系統不能告訴你,如果一個類有一個默認的構造函數。請記住,案例類通常不具有默認構造函數,因爲不建議使用無參數的案例類。默認構造函數的概念對於不可變對象不是很有用。 AFAIK沒有理由不原則上(Scala確實支持結構類型,其中類型必須具有特定名稱的方法),但它需要語言更改。你可以在運行時檢查反射,但這不是你想要的。

但是,您可以使用類型類模式強制默認值是在範圍之內。這在概念上與添加OP中建議的額外默認論證非常相似,但使用隱含來隱藏它們。它在收藏庫中大量使用。 missingfaktor的回答使用scalaz.Zero就是這方面的一個特例,但是在vanilla Scala中這樣做並不容易,而且對於一些任意的默認值,這不一定是某種零。

case class Default[T](default: T) 

case class Foo(value: String) 
case class Bar(value: Int) 

implicit val fooDefault = Default(Foo("I'm a default Foo")) // note 1 

現在讓我們來看一個例子用法:

def firstItem[T](lst: List[T]) (implicit ev: Default[T]) = // note 2 
    if (lst.isEmpty) ev.default else lst.head 

val fooList  = List(Foo("cogito"), Foo("ergo"), Foo("sum")) 
val emptyFooList = List[Foo]() 
val barList  = List(Bar(101), Bar(102)) 
val emptyBarList = List[Bar]() 

firstItem(fooList)      // Foo("cogito") 
firstItem(emptyFooList)     // Foo("I'm a default Foo") 
firstItem(barList)      // ** error: missing implicit ** 

所以我們看到,這個編譯與List[Foo],但List[Bar]是不能接受的,因爲沒有隱含Default[Bar](注3)。


注1:此隱含可以在object Foo被定義 - 這將確保它的範圍,如果你導入類的其他地方。但它不一定是:你也可以爲任意類定義類似的暗示,IntString,不管(嘗試它)。注意2:這相當於加糖版本def firstItem[T: Default](lst: List[T]) = ...,你在那裏召喚evimplicitly[Default[T]]。拿你的選擇。

注3:我們可以把它簡單地提供一個工作:

firstItem(barList)(Default(Bar(42)))  // Bar(101) 
firstItem(emptyBarList)(Default(Bar(42))) // Bar(42)