2015-11-27 7 views
4

Скажем, у меня есть специализированный класс и связанный с ним сопутствующий объект:Как проверить, что я внутри функции или класса @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 или передавая класс [_] вручную? Похоже, эта информация должна быть доступна, но единственный способ, который я могу представить, - проверить имена классов.

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

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

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

+1

Вы действительно хотите, чтобы проверить из функции? Любая проверка будет потреблять всю выгоду от специализации. Кроме того, что не так с проверкой имен классов 'x.getClass.getName.endsWith (" $ sp ")'? Я использую это в некоторых модульных тестах, чтобы убедиться, что специализация работает (но извне) –

+1

Нет, если проверка и бросок выполняются в коллекции и исключают бокс, выполняемый в цикле. Проблема с проверкой суффикса класса nake заключается в том, что проверенный экземпляр может быть специализацией в виде субтракта, расширяя стертую версию этого признака. Добавьте вложенные классы, и такой код будет очень сложным, чтобы получить право, не говоря о хрупкой зависимости от схемы именования, используемой компилятором. – Turin

ответ

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 Теперь возвращает класс, соответствующий параметру специализации Е.