Как избежать накладных расходов, чтобы передать карту [Integer, String], где ожидается карта [Number, String]? - PullRequest
0 голосов
/ 07 мая 2011

Проблема: У меня есть mutable.Map [Integer, String], я хочу передать его двум методам:

  1. def processNumbers (nums: Map [Number, String])
  2. def processIntegers (nums: mutable.Map [Integer, String])

после получения ошибки компиляции я получил следующее:

val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
//init of ints
val nums: Map[Number, String] = ints.toMap[Number, String]
processNumbers(nums)
processIntegers(ints)

С небольшим экспериментом я понял, что мой способ сделать это имеет значительные накладные расходы: шаг преобразования типа умножить на 10 на время выполнения.
В общем, преобразование типов действительно просто для того, чтобы порадовать компилятор, так как же это сделать без каких-либо накладных расходов?

Для информации, код моего эксперимента:

package qndTests
import scala.collection.mutable
object TypeTest {
  var hashNums = 0
  var hashIntegers = 0
  def processNumbers(nums: Map[Number, String]): Unit = {
  nums.foreach(num =>{
      hashNums+=num._1.hashCode+num._2.hashCode
    })
  }
  def processNumbers2(nums: mutable.Map[Integer, String]): Unit = {
  nums.foreach(num =>{
      hashNums+=num._1.hashCode+num._2.hashCode
    })
  }
  def processIntegers(nums: mutable.Map[Integer, String]): Unit = {
  nums.foreach(num =>{
      hashIntegers+=num._1.hashCode+num._2.hashCode
    })
  }
  def test(ints: mutable.Map[Integer, String], convertType: Boolean): Unit = {
  if(convertType)
    println("run test with type conversion")
  else
    println("run test without type conversion")

  val start = System.nanoTime
  hashNums = 0
  hashIntegers = 0
  val nTest = 10
  for(i <- 0 to nTest) {
    if(convertType){
      val nums: Map[Number, String] = ints.toMap[Number, String] //how much does that cost ?
      processNumbers(nums)
    }else{
      processNumbers2(ints)
    }

    processIntegers(ints)
  }
  val end= System.nanoTime
  println("nums: "+hashNums)
  println("ints: "+hashIntegers)
  println(end-start)
}
def main(args: Array[String]): Unit = {
  val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
  val testSize = 1000000

  println("creating a map of "+testSize+" elements")
  for(i <- 0 to testSize) ints.put(i, i.toBinaryString)
  println("done")

  test(ints, false)
  test(ints, true)
  }
}

и его вывод:

создание карты из 1000000 элементов
сделано
запустить тест без преобразования типа
номера: -1650117013
целое число: -1650117013
2097538520
запустить тест с преобразованием типов
номера: -1650117013
целое число: -1650117013
25423803480

-> около 2 секунд в первом случае против 25 секунд во втором!

1 Ответ

3 голосов
/ 07 мая 2011

Как вы видели, Map[A,B] является невариантным в типе ключа A, поэтому вам потребуется какое-то преобразование для присвоения переменной типа Map[A,B] a Map[A1,B], где A1 <: A , Однако, если вы можете изменить определение def processNumbers(nums: Map[Number, String]), вы можете попробовать что-то вроде:

def processNumbers[T <: Number](nums: Map[T, String])

и передать Map[Integer, String] без преобразования.

Поможет ли это решить вашу проблему?

...