Как проверить, что я нахожусь внутри @specialized функции или класса во время выполнения в Scala?

Допустим, у меня есть специализированный класс и связанный с ним объект-компаньон:

trait Slice[@specialized +T] {
    ...

    override def equals(that :Any) = that match {
        case s :Slice[_] => ???
        case _ => false
    }
}

object Slice {
    def newInstance[@specialized T] = ???
}

Есть ли способ проверить

  1. Внутри метода Slice, если этот экземпляр является специализированным подклассом,
  2. Внутри метода Slice, если другой экземпляр является специализированным подклассом для того же примитива,
  3. Внутри специализированного метода на объекте-компаньоне, если я запускаю стертый или специализированный вариант

не прибегая к ClassTags или передавая Class[_] вручную? Кажется, эта информация должна быть доступна, но единственный способ, которым я могу придумать, - это проверка имен классов.

Вариант использования 2) особенно важен, так как я мог бы прибегнуть к более быстрым алгоритмам, если я впервые сравниваю яблоки с яблоками. Вероятно, это может быть достигнуто с помощью рефлексии, но это будет довольно сложно, если учесть, что мы должны обрабатывать и не синтетические подклассы Slice; если у нас есть также

trait ArraySlice[@specialized T] extends Slice[T] { ... }

что следует считать "совместимым" с экземплярами Slice[T], если они оба специализированы (или оба стерты)?

1 ответ

Решение

Хорошо, я понял более чистый способ:

final val AllButUnit = new Specializable.Group((Byte, Short, Int, Long, Char, Float, Double, Boolean, AnyRef))

def specializationFor[@specialized(AllButUnit) E] :ResolvedSpecialization[E] =
    Specializations(new SpecializedKey[E]).asInstanceOf[ResolvedSpecialization[E]]


private val Specializations = Seq(
    resolve[Byte],
    resolve[Short],
    resolve[Int],
    resolve[Long],
    resolve[Char],
    resolve[Float],
    resolve[Double],
    resolve[Boolean],
    resolve[Unit],
    resolve[AnyRef]
).map(
    spec => spec.key -> spec :(SpecializedKey[_], ResolvedSpecialization[_])
).toMap.withDefaultValue(resolve[AnyRef])

private def resolve[@specialized(AllButUnit) E :ClassTag] :ResolvedSpecialization[E] =
    new ResolvedSpecialization[E](new SpecializedKey[E], new Array[E](0))


class ResolvedSpecialization[@specialized(AllButUnit) E] private[SpecializedCompanion]
        (val array :Array[E], val elementType :Class[E], val classTag :ClassTag[E], private[SpecializedCompanion] val key :SpecializedKey[E])
{
    private[SpecializedCompanion] def this(key :SpecializedKey[E], array :Array[E]) =
        this(array, array.getClass.getComponentType.asInstanceOf[Class[E]], ClassTag(array.getClass.getComponentType.asInstanceOf[Class[E]]), key)

    override def toString = s"@specialized($elementType)"

    override def equals(that :Any) = that match {
        case r :ResolvedSpecialization[_] => r.elementType==elementType
        case _ => false
    }

    override def hashCode = elementType.hashCode
}

private class SpecializedKey[@specialized(AllButUnit) E] {
    override def equals(that :Any) = that.getClass==getClass
    override def hashCode = getClass.hashCode

    def className = getClass.getName
    override def toString = className.substring(className.indexOf("$")+1)
}

Сейчас specializationFor[E].elementType возвращает класс, соответствующий параметру специализации E.

Другие вопросы по тегам