2014-01-22 39 views
1

具有完全适合多种类型的隐式实例实现我需要为特定类型提供具体实例的模块。以下是我尝试以“蛋糕模式”的精神实现这一点的相似之处。提供具有不同类型参数的相同隐式专用的多个实例

trait Show[ a ]{ 
    def show(a: a): String 
} 
trait PrimitiveShowInstance[ a ] { 
    implicit def primitiveShowInstance = new Show[ a ] { 
    def show(a: a) = a.toString 
    } 
} 
object SomeModule 
    extends PrimitiveShowInstance[ Int ] 
    with PrimitiveShowInstance[ String ] 
    with PrimitiveShowInstance[ Boolean ] 

上述代码无法编译抱怨继承两次相同的特质。这显然只是一个例子,实际情况下,隐式转换的签名涉及更多 - 它包含其他含义和大量的类型参数。因此,引入“别名”方法不是一种选择,因为由于Scala的语法不可行性,我仍然需要复制粘贴方法签名。

如何解决这个问题?

回答

0

以下是一个允许只写一次primitiveShowInstance的实现的解决方案,这就是为什么它可以完美地适用于更多涉及的案例。这个想法非常简单:我们引入另一个隐含的,它只作为支持某种类型实现的证据。

trait Show[ a ]{ 
    def show(a: a): String 
} 
trait PrimitiveShowInstance { 
    implicit def primitiveShowInstance[ a ](implicit support: Support[ a ]) = 
    new Show[ a ] { 
     def show(a: a) = a.toString 
    } 
    // Simply an evidence of support for this by type `value`. 
    class Support[ value ] 
} 
object SomeModule extends PrimitiveShowInstance { 
    implicit val intPrimitiveShowInstanceSupport = new Support[Int] 
    implicit val stringPrimitiveShowInstanceSupport = new Support[String] 
} 
4

在这种情况下,您真正​​体验到的是类型擦除的问题。你真正想要做的是以下几点:

object SomeModule{ 
    implicit val primInt = new Show[Int}{ 
    def show(a: Int) = a toString() 
    } 
    //and so on for each "A" 
} 

其中,你要确保你总是包含include SomeModule._使得implicits都在范围之内。这允许你放弃在你的PrimitiveShowInstance特性中甚至有implicit def primiteShowInstance方法的需要。

一个人出行方式,正是你所看到的仅仅是庸俗而:

trait SomeFoo{ 
    self: WithIntFoo with WithDoubleFoo => 
} 

等。是的,丑陋。是的,有时并不美妙。但是,这将解决类型过时的问题,并多次实现相同的特征。

+0

谢谢,但所有这一切的重点正是无法为每种特定类型编写实现。无论如何,我已经提出了解决方案,查看我的答案。 –

+0

@NikitaVolkov我认为你的实际用例必须比你上面发布的示例代码复杂得多,因为看起来你的解决方案就是这样,为每一个明确写出另一个东西。 – wheaties

+0

是的,但该解决方案是关于更少的额外键入和更容易推理然后复制粘贴[这样的代码](http://stackoverflow.com/q/21289925/485115),这是一个签名示例I必须处理。 –

相关问题