通用特征的隐式转换

发布于 2024-10-14 18:42:07 字数 1094 浏览 10 评论 0原文

我正在实现一个数据结构,并希望用户能够使用任何类型作为密钥,只要他提供一个合适的密钥类型来包装它。我有这个关键类型的特征。这个想法是进行从基类型到键类型的隐式转换,反之亦然(实际上)仅使用基类型。该特征如下所示:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T

  // Further stuff needed for datastructure...
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
}

调用站点代码可能如下所示:

def foo[K <% Key[K]]( bar : Seq[K] ) = bar.sorted(0)

计划是 K 类型的值应隐式转换为已排序的 Key[K] 或排序on Key[K] 应该分别隐式使用,因此一切都应该正常。当然,没有办法在特征本身中实现隐式base2key。或者是否存在,可能使用隐式传递的类清单?考虑到这一点,我找不到任何参考资料。

是否可以以某种方式静态断言任何扩展 Key[T] 的类型都将带有隐式转换 T =>键[T]?遗憾的是,伴生对象不能有抽象方法。

假设这可行,整个企业是否可行,或者所述用例是否需要多个链式隐式转换? (正如我所读到的,链接不会发生。)

附录:通过上面的定义,我可以对 Node(key : K, ...) 的序列进行排序(在K <% Key[K]),使用 sortWith(_.key <= _.key),但不使用 sortBy(_.key)。因此,显然,从 KKey[K] 的转换是隐式发生的,即使我从未在任何地方声明过它,但没有 OrderingKey[K] 上的 code> 隐式可用。这是怎么回事?

I am implementing a datastructure and want the user to be able to use any type as key as long as he provides a suitable key type wrapping it. I have a trait for this key type. The idea is to have implicit conversions from base to key type and the other way round to (virtually) just use the base type. The trait looks like this:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T

  // Further stuff needed for datastructure...
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
}

Call site code could look like this:

def foo[K <% Key[K]]( bar : Seq[K] ) = bar.sorted(0)

Plan is that values of type K should be implicitly converted to Key[K] which is ordered or the ordering on Key[K] should be implcitly used, respectively, so everything should work out. Of course, there is no way to implement implicit base2key in the trait itself. Or is there, maybe using implicitly passed class manifests? I could not find any references considering this.

Is it possible to somehow assert statically that any type extending Key[T] will come with an implicit conversion T => Key[T]? The companion object can not have abstract methods, sadly.

Assume this works out, is the entire enterprise feasible or will the stated use case need multiple chained implicit conversions, anyway? (Chaining does not happen, as I have read.)

Addendum: With above definition, I can sort a sequence of Node(key : K, ...) (under K <% Key[K]) by using sortWith(_.key <= _.key), but not using sortBy(_.key). So, obviously, the conversion from K to Key[K] happens implicitly, even though it is never declared anywhere by me, but there is no Ordering on Key[K] available implicitly. What is going on here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

伴随着你 2024-10-21 18:42:07

你问“是否有可能以某种方式静态断言任何扩展 Key[T] 的类型都将带有隐式转换 T => Key[T]?遗憾的是,不能有抽象方法。”

但您的示例是静态断言:当您需要从 TKey[T] 的视图时,您在编译时断言只能调用 foo< /code> 用于可以提升为键的类型。或者我误解了什么?

关于附录:您说您对“从 KKey[K] 的转换隐式发生感到惊讶,即使我从未在任何地方声明过它”。事情是,你确实声明了它: T <% Key[T] (我在这里使用 T 而不是 K,你似乎在这里混淆了基本 *T*ype 和 *K*ey 的概念吗?)。这与因此相同

def foo[T](bar : Seq[T])(implicit view: T => Key[T]) = bar.sortWith(_ <= _)(0)

,当您执行 sortWith(_ <= _) 时,您将 T 强制转换为 Key[T] (对于其中 < code><= 根据特征 Ordered[Key[T]] 定义)。

以您的 Node 为例,为什么不希望

case class Node[K](key: K)
def test[K](bar: Seq[Node[K]])(implicit ord: Ordering[K]) = bar.sortBy(_.key)(0)

有所帮助......

you ask "Is it possible to somehow assert statically that any type extending Key[T] will come with an implicit conversion T => Key[T]? The companion object can not have abstract methods, sadly."

but your example is a static assertion : when you require a view from T to Key[T], you assert at compile time that you may only call foo for types which can be lifted to keys. Or am i misunderstanding something?

regarding the addendum: you say you are surprised that "the conversion from K to Key[K] happens implicitly, even though it is never declared anywhere by me". thing is, you did declare it: T <% Key[T] (I am using T here instead of K, you seem to be mixing up the notion of base *T*ype and *K*ey here?). This is identical to

def foo[T](bar : Seq[T])(implicit view: T => Key[T]) = bar.sortWith(_ <= _)(0)

thus, when you do sortWith(_ <= _) you coerce T into Key[T] (for which <= is defined as per trait Ordered[Key[T]]).

taking your Node example, why not do

case class Node[K](key: K)
def test[K](bar: Seq[Node[K]])(implicit ord: Ordering[K]) = bar.sortBy(_.key)(0)

hope that helps...

莳間冲淡了誓言ζ 2024-10-21 18:42:07

这是您问题的可能解决方案(希望我正确理解您的要求):

// Key stuff

trait Keyable[T] {
  def toKey(t: T): Key[T]
}

trait Key[T] extends Ordered[Key[T]] {
  def toBase() : T
}

object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def base2key[T : Keyable](k : T) : Key[T] = implicitly[Keyable[T]].toKey(k)
}

// more concrete stuff - namely A

class A(val i: Int) {
  override def toString = "A {" + i + "}"
}

object A {
  implicit val aKeyable = new Keyable[A] {
    def toKey(t: A) = new Key[A] {
      def toBase() = t
      def compare(that: Key[A]) = t.i compare that.i
    }
  }
}

// testing

def foo[K : Keyable](bar: Seq[K]) = bar.sortBy(implicitly[Keyable[K]].toKey)

val list = List(new A(5), new A(1), new A(3))

println(foo(list)) // prints: List(A {1}, A {3}, A {5})

在这种情况下,Key[T] 是类型 TKeyable[T] 的包装器 是类型调用,允许将类型 T 转换为 Key[T]。我还展示了 base2key 的样子。

Here is possible solution to your problem (hope I understood your requirements correctly):

// Key stuff

trait Keyable[T] {
  def toKey(t: T): Key[T]
}

trait Key[T] extends Ordered[Key[T]] {
  def toBase() : T
}

object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def base2key[T : Keyable](k : T) : Key[T] = implicitly[Keyable[T]].toKey(k)
}

// more concrete stuff - namely A

class A(val i: Int) {
  override def toString = "A {" + i + "}"
}

object A {
  implicit val aKeyable = new Keyable[A] {
    def toKey(t: A) = new Key[A] {
      def toBase() = t
      def compare(that: Key[A]) = t.i compare that.i
    }
  }
}

// testing

def foo[K : Keyable](bar: Seq[K]) = bar.sortBy(implicitly[Keyable[K]].toKey)

val list = List(new A(5), new A(1), new A(3))

println(foo(list)) // prints: List(A {1}, A {3}, A {5})

In this case Key[T] is wrapper for type T and Keyable[T] is type calss that allows to convert type T to Key[T]. I also showed how base2key can look like.

活泼老夫 2024-10-21 18:42:07

在这个答案中,我会保留目前最好的版本以供参考。使用这个答案可以更加集中问题;根据 这个 < /a>.

Key 特征保持不变;我添加了一个特定的函数来进行说明:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T
  def foo(i : Int) : Key[T]
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def ordering[T <% Key[T]] = new Ordering[T]{
    def compare(x: T, y: T) = x compare y
  }
}

以下内容按预期工作(如果完成了 import Key._):

def min[K <% Key[K]](l : Seq[K]) : K = l.sorted.head

让我们假设我们有一个简单的 class Node[K](val key : K )。同样,事情按预期进行:

def min[K <% Key[K]](l : Seq[Node[K]]) : Node[K] = l.sortBy(_.key).head

再举一个例子,假设此代码仅使用 Key[T] 接口:

def test[K <% Key[K]](bar : Seq[K]) = 
  bar.map(_.foo(3)).sorted

请注意,由于 map 生成 Seq[直接Key[K]];排序不需要转换。现在,如果我们有 Key 的正确实现,那么

class StringKey(val key : String) extends Key[String] {
  def foo(i : Int) =  StringKey(this.key + "_" + i)
  def toBase = key
  override def compare(other : Key[String]) = -1*this.key.compare(other.toBase)
}
object StringKey {
  def apply(key : String) = new StringKey(key)
  def unapply(key : String) = Some(key)
  implicit def string2key(s : String) = StringKey(s)
}

下面的内容应该可以工作:

import StringKey.string2key
import Key.key2base
val bla : Seq[String] = test(Seq("b", "c", "a")).map(_.capitalize)
println(bla)
// expected output: Seq(C_3, B_3, A_3)

但实际上,没有找到从 StringKeyString 的转换:

error: value capitalize is not a member of this.Key[java.lang.String]

这很奇怪;如果使用泛型类型参数声明,则存在从 Key[String]String 的转换。

In this answer, I will keep the currently best version for reference. Using this answer to more focused question; will be obsolete with 2.9 according to this one.

The Key trait remains unchanged; I add a specific function for illustration:

trait Key[T] extends Ordered[Key[T]] {
  def toBase : T
  def foo(i : Int) : Key[T]
}
object Key {
  implicit def key2base[T](k : Key[T]) : T = k.toBase
  implicit def ordering[T <% Key[T]] = new Ordering[T]{
    def compare(x: T, y: T) = x compare y
  }
}

The following works as expected (if import Key._ is done):

def min[K <% Key[K]](l : Seq[K]) : K = l.sorted.head

Let us assume we have a simple class Node[K](val key : K). Again, things work as expected:

def min[K <% Key[K]](l : Seq[Node[K]]) : Node[K] = l.sortBy(_.key).head

For another example, assume this code using only the Key[T] interface:

def test[K <% Key[K]](bar : Seq[K]) = 
  bar.map(_.foo(3)).sorted

Note that this compiles since map yields a Seq[Key[K]] directly; no conversion needed for sorting. Now, if we have a proper implementation of Key, say

class StringKey(val key : String) extends Key[String] {
  def foo(i : Int) =  StringKey(this.key + "_" + i)
  def toBase = key
  override def compare(other : Key[String]) = -1*this.key.compare(other.toBase)
}
object StringKey {
  def apply(key : String) = new StringKey(key)
  def unapply(key : String) = Some(key)
  implicit def string2key(s : String) = StringKey(s)
}

the following should work:

import StringKey.string2key
import Key.key2base
val bla : Seq[String] = test(Seq("b", "c", "a")).map(_.capitalize)
println(bla)
// expected output: Seq(C_3, B_3, A_3)

But actually, the conversion from StringKey to String is not found:

error: value capitalize is not a member of this.Key[java.lang.String]

This is strange; there is a conversion from Key[String] to String, if declared with a generic type parameter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文