简体   繁体   中英

Scala class with a private constructor and implicit parameter

I would like to add an implicit parameter to a class with a private constructor. Here as a simplified example:

class A[T] private(a:Int){ 
  def this()=this(0)
}

If I would like to apply Pimp my library pattern to T with Ordered[T], I would need to use (the deprecated) view bound like so:

class A[T <% Ordered[T]] private(a:Int){ 
  def this()=this(0)
}

And this works. However, to avoid the deprecated syntactic sugar I would like to pass the implicit parameter to the class. Unfortunately, this is where I'm probably doing something wrong:

class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){ 
  def this()=this(0)
}

For the above code, the compiler generates the following error:

error: No implicit view available from T => Ordered[T].
       def this()=this(0)

While if I try to pass the implicit parameter directly like so:

class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){ 
  def this()=this(0)(conv)
}

I get this:

error: not found: value conv
       def this()=this(0)(conv)

How does one pass an implicit parameter in this case?

EDIT: After some more experimentation it seems that redefining the constructor with implicit parameter is the problem. Not the fact that the constructor is private.

I found an answer, it seems that I need to explicitly define the implicit parameter for the parameterless constructor, eg:

class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){ 
  def this()(implicit conv:T=>Ordered[T])=this(0)
}

I apologize for spamming SO, in any case I will accept any answer that provides a more in depth explanation.

Scala provides ordering in 2 flavours, one via inheritance with Ordered and the other one which is actually a lot more appropriate in here is via context bounds using the Ordering typeclass.

Your approach is not actually idiomatic, and if you had something that actually used the implicit you provided, you would get an ambiguous implicit exception at compile time, because both the constructor and the method define the same implicit.

What I would do is:

class A[T : Ordering] private(a: Int)

This is actually shorthand syntax for:

class A[T] private(a: Int)(implicit ev: Ordering[T])

You can then use this argument either explicitly or implicitly . If you define it with the shorthand T : Ordering syntax.

class A[T : Ordering] private(a: Int) {
  def revSorter(list: List[T]): List[T] = {
    list.sorted(implicitly[Ordering[T]].reverse)
  }
}

If you define it with the "explicit" syntax:

class A[T] private(a: Int)(implicit ev: Ordering[T]) {
      def revSorter(list: List[T]): List[T] = {
        list.sorted(ev.reverse)
      }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM