سؤال

أرى مشكلة في بعض كود Scala 2.7.7 الذي أعمل عليه ، لا ينبغي أن يحدث ذلك إذا تم كتابة المكافئ في Java. بشكل فضفاض ، ينشئ الرمز مجموعة من مشغلات البطاقات ويعينهم إلى الجداول.

class Player(val playerNumber : Int)

class Table (val tableNumber : Int) {
    var players : List[Player]  = List()

    def registerPlayer(player : Player) {
        println("Registering player " + player.playerNumber + " on table " + tableNumber)
        players = player :: players
    }
}

object PlayerRegistrar  {
    def assignPlayersToTables(playSamplesToExecute : Int, playersPerTable:Int) = {
        val numTables = playSamplesToExecute / playersPerTable
        val tables = (1 to numTables).map(new Table(_))
        assert(tables.size == numTables)

        (0 until playSamplesToExecute).foreach {playSample =>
            val tableNumber : Int = playSample % numTables
            tables(tableNumber).registerPlayer(new Player(playSample))
        }
        tables
    }
}

يقوم PlayerRegistrar بتعيين عدد من اللاعبين بين الجداول. أولاً ، يعمل على عدد الجداول التي سيحتاج إلى تفكيك اللاعبين بينهم وإنشاء قائمة منها.

ثم في الجزء الثاني من الكود ، يعمل على الجدول الذي يجب تعيينه لاعبه ، يسحب هذا الجدول من القائمة ويسجل لاعبًا جديدًا على هذا الجدول.

قائمة اللاعبين على الطاولة هي VAR ، ويتم الكتابة فوقها في كل مرة يتم استدعاء registerPlayer (). لقد راجعت أن هذا يعمل بشكل صحيح من خلال اختبار testng بسيط:

@Test def testRegisterPlayer_multiplePlayers() {
    val table = new Table(1)
    (1 to 10).foreach { playerNumber =>
        val player = new Player(playerNumber)
        table.registerPlayer(player)
        assert(table.players.contains(player))
        assert(table.players.length == playerNumber)
    }
}

ثم أختبر تعيين الجدول:

  @Test def testAssignPlayerToTables_1table() = {
    val tables = PlayerRegistrar.assignPlayersToTables(10, 10)
    assertEquals(tables.length, 1)
    assertEquals(tables(0).players.length, 10)
}

فشل الاختبار مع "المتوقع: <10> ولكن كان: <0>". لقد كنت أخدش رأسي ، لكن لا يمكنني معرفة سبب قيام RegisterPlayer () بتمرير الجدول في القائمة. سيكون موضع تقدير أي مساعدة.

هل كانت مفيدة؟

المحلول

السبب هو أنه في assignPlayersToTables الطريقة ، أنت تقوم بإنشاء جديد Table هدف. يمكنك تأكيد ذلك بإضافة بعض التصحيح إلى الحلقة:

val tableNumber : Int = playSample % numTables
println(tables(tableNumber))
tables(tableNumber).registerPlayer(new Player(playSample))

تسفر عن شيء مثل:

Main$$anon$1$Table@5c73a7ab
Registering player 0 on table 1
Main$$anon$1$Table@21f8c6df
Registering player 1 on table 1
Main$$anon$1$Table@53c86be5
Registering player 2 on table 1

لاحظ كيف يختلف عنوان ذاكرة الجدول لكل مكالمة.

سبب هذا السلوك هو أن أ Range هو غير مكثف في Scala (حتى Scala 2.8 ، على أي حال). هذا يعني أنه لا يتم تقييم الدعوة إلى النطاق حتى تكون هناك حاجة إليها. لذلك تعتقد أنك تعود إلى قائمة من Table الكائنات ، ولكن في الواقع ستعود إلى نطاق يتم تقييمه (إنشاء إنشاء جديد Table كائن) في كل مرة تسميها. مرة أخرى ، يمكنك تأكيد ذلك بإضافة بعض تصحيح الأخطاء:

val tables = (1 to numTables).map(new Table(_))
println(tables)

الذي يمنحك:

RangeM(Main$$anon$1$Table@5492bbba)

لفعل ما تريد ، أضف أ toList إلى النهاية:

val tables = (1 to numTables).map(new Table(_)).toList

نصائح أخرى

val tables = (1 to numTables).map(new Table(_))

يبدو أن هذا الخط يسبب كل المشاكل - رسم الخرائط 1 to n يعطيك RandomAccessSeq.Projection, ولكي أكون صادقًا ، لا أعرف كيف يعملون بالضبط ، لكن تقنية التهيئة الأقل ذكاءً تقوم بالمهمة.

var tables: Array[Table] = new Array(numTables)
for (i <- 0 to numTables) tables(i) = new Table(i)

باستخدام طريقة التهيئة الأولى ، لم أتمكن من تغيير الكائنات (مثلك تمامًا) ، ولكن باستخدام صفيف بسيط يبدو أن كل شيء يعمل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top