我使用Scala隐式类来扩展我经常使用的对象.作为一个例子,我有一个类似于Spark上定义的方法DataFrame:
implicit class DataFrameExtensions(df: DataFrame) {
def deduplicate: Boolean =
df.groupBy(df.columns.map(col): _*).count
}
Run Code Online (Sandbox Code Playgroud)
但是如果类已经定义了相同的方法,则不会调用隐式defs.如果我以后升级到定义DataFrame#deduplicate方法的新版Spark,会发生什么?客户端代码将静默切换到新的实现,这可能会导致细微的错误(或明显的错误,这些问题较少).
使用反射,如果在我的隐式定义它之前已经定义,我可以抛出运行时错误.从理论上讲,如果我的隐式方法与现有方法冲突,我可以检测它并重命名我的隐式版本.但是,一旦我升级Spark,运行应用程序并检测问题,使用IDE重命名旧方法为时已晚,因为现在任何引用都引用了本机Spark版本.我将不得不恢复我的Spark版本,通过IDE重命名该方法,然后再次升级.不是世界末日,而是一个伟大的工作流程.DataFramededuplicatedf.deduplicate
有没有更好的方法来处理这种情况?如何安全地使用"皮条客我的图书馆"模式?
为了减少项目的编译时间,我正在缓存某些通过隐式查找解析的类型类.这看起来有些麻烦,因为直接实现不起作用:
scala> implicit val x: String = implicitly[String]
x: String = null
Run Code Online (Sandbox Code Playgroud)
隐式查找将其自己的未初始化定义视为有效实现.A lazy val会以无限递归的方式吹制堆栈.因此,我正在以这种方式处理它:
implicit val x: String = cache.x
object cache {
val x: String = implicitly[String]
}
Run Code Online (Sandbox Code Playgroud)
但这使得它过于复杂,并且缓存定义不能轻易地使用其他缓存类型(因为它们不是隐式的).
此外,遗憾的是,将值本身隐藏在范围内并不起作用.
scala> :pas
// Entering paste mode (ctrl-D to finish)
object scope {
implicit val x: String = {
import scope.{ x => _ }
implicitly[String]
}
}
// Exiting paste mode, now interpreting.
defined object scope
scala> scope.x
res0: String = null
Run Code Online (Sandbox Code Playgroud)
是否有更优雅的方法来实现隐式解析缓存?
Intellij错误地标记了一些Scala implicits导入为不使用.有没有办法阻止它在为特定导入明确优化它们时删除那些导入,而不是阻止整个项目的优化导入?
以下Haskell类型类和实例:
class Able a where
able :: a -> Int
instance Able Int where
able x = x
Run Code Online (Sandbox Code Playgroud)
通常被翻译成Scala,如下所示:
trait Able[A] {
def able(a: A): Int
}
implicit object AbleInt extends Able[Int] {
def able(a: Int) = a
}
Run Code Online (Sandbox Code Playgroud)
在Haskell中,我现在可以定义一种catch-all实例,从而为所有Maybe类型创建一个实例:
instance Able a => Able (Maybe a) where
able (Just a) = able a
able Nothing = 0
Run Code Online (Sandbox Code Playgroud)
这定义的一个实例Able为Maybe Int,Maybe Bool等条件是在一个实例Able为Int,Bool等等.
如何在Scala中做到这一点?
我有以下Scala代码片段:
import java.io.PrintWriter
trait Write[-A] {
def apply(out: PrintWriter)(x: A): Unit
}
trait LowPriorityWrites {
implicit object any extends Write[Any] {
override def apply(out: PrintWriter)(x: Any) = out.print(x)
}
}
object Write extends LowPriorityWrites {
implicit def iterable[A](implicit write: Write[A]): Write[Traversable[A]] = new Write[Traversable[A]] {
override def apply(out: PrintWriter)(xs: Traversable[A]) = {
xs foreach write(out)
out.println()
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,我想要实现的是首先寻找隐含的Write对象.如果不能,回落到默认.toString为Any从LowPriorityWrites.
但是,这种方法不起作用:
ambiguous implicit values:
[error] both method iterable in object Write of …Run Code Online (Sandbox Code Playgroud) 我在scalaLang的Twitter上发现了一篇有趣的帖子.此代码编译和工作的位置
class A(implicit implicit val b: Int)
val objA = new A()(42)
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下它是如何工作的?我阅读了implicits的文档,但没有找到这样的案例.请解释一下这里发生了什么.
任何帮助表示赞赏!
我有以下代码,它应该采用一个函数A => Boolean(输入类型的通用)并Y[A]通过链式隐式转换将其转换为通用特征:
val f: Int => Boolean = ???
trait X[A] {
def m1: Unit
}
implicit def toX[A](f: A => Boolean): X[A] = ???
f.m1 // Works
trait Y[A] {
def m2: Unit
}
implicit def toY[T, A](x: T)(implicit toX: T => X[A]): Y[A] = ???
f.m2 // Won't compile
Run Code Online (Sandbox Code Playgroud)
不幸的是,最后一行不会编译.
执行以下任何一项更改就足以使代码编译:
X非泛型Y非泛型Int => A)上使用泛型函数替换源类型(在输入类型上是通用函数)Option[A],Seq[A]或Array[A]基于此,我的结论是隐式转换链不起作用,因为源类型(输入类型的泛型函数)是通用的和逆变的 …
考虑以下代码:
trait Foo {
type T
def value: T
}
object Foo {
def apply[A](v: A): Foo = new Foo {
override type T = A
override def value = v
}
}
trait Decode[A] {
def apply(x: A): String
}
object Decode {
def apply[A](f: A => String): Decode[A] = new Decode[A] {
override def apply(x: A) = f(x)
}
implicit val decodeStr: Decode[String] = Decode(identity)
}
class Sandbox {
def decodeFoo(foo: Foo)(implicit decoder: Decode[foo.T]): String =
decoder(foo.value)
val …Run Code Online (Sandbox Code Playgroud) 我奋力关于如何创建的实例Functor[Dataset]...问题是,当你map从A到B了Encoder[B]必须在隐含的范围,但我不知道该怎么做.
implicit val datasetFunctor: Functor[Dataset] = new Functor[Dataset] {
override def map[A, B](fa: Dataset[A])(f: A => B): Dataset[B] = fa.map(f)
}
Run Code Online (Sandbox Code Playgroud)
当然这个代码抛出一个编译错误,因为Encoder[B]不可用,但我不能添加Encoder[B]为隐式参数,因为它会改变map方法签名,我该如何解决?
scala apache-spark scala-cats scala-implicits apache-spark-encoders
这是一个奇怪的情况:
如果我注释掉feed_usingExplicitTypeClassInstance下面的调用,那么我会收到编译器错误.
非常令人费解.任何解释?
我的意思是,我注释掉一个函数调用(它没有返回任何值),然后代码不再编译?
在理论上这应该是可能的吗?在任何编程语言?
我的意思是我评论出类似的东西println("hello")然后代码不再编译?
当然,如果我将注释掉一个声明或者其他内容,但是调用一个不返回任何内容的函数,那将是可以理解的.
object AnimalFeeder extends App {
def feed_usingExplicitTypeClassInstance[AnimalInstance]
(animalTypeClass: AnimalTypeClass[AnimalInstance])
(food: animalTypeClass.FoodThatAnimalLikes) =
{
animalTypeClass.feed(food)
}
def feed_usingImplicitTypeClassInstance[AnimalInstance, Food]
(food: Food)
(implicit animalTypeClass: AnimalTypeClass.Aux[Food,AnimalInstance]) =
{
animalTypeClass.feed(food)
}
// If I comment out this line, THEN !, I get an error !!!! How ???
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())
feed_usingImplicitTypeClassInstance(new CatFood)
}
trait Food {
def eat(): Unit
}
trait AnimalTypeClass[AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f: FoodThatAnimalLikes) = …Run Code Online (Sandbox Code Playgroud) scala ×10
scala-implicits ×10
implicit ×3
typeclass ×2
apache-spark ×1
generics ×1
haskell ×1
implicits ×1
import ×1
scala-cats ×1