2016-07-25 49 views
2

我已經定義了一個對象數據,用於存儲我用於代碼的各種數據位。我想在運行時插入一個新房間。例如一個變量的新鍵「R200」,但目前爲止尚未能夠實現。haxe爲變量添加新對象

static public var data = 
{ 
    room: { 
     "R100": {monstersLeft: 2 } 
    } 
} 


// need to add the the object data : 
// would like to reference is like: 
var newRoom = "R200"; 
???? data[newRoom ].monstersLeft = 5; 

trace(data.R200.monstersLeft) 

回答

4

Haxe的anonymous structures只不過是無類型的,有組織的數據集合。它們的結構一旦設置就不可改變,只有屬性值可以修改。數組訪問(括號表示法)未在匿名結構中定義 - 而是使用點表示法。

由於匿名結構的無類型(動態)性質,編譯爲靜態目標時它們可以有一個negative impact on performance

建議使用typedefstypedef extensions組織和鍵入匿名結構。這確保了類型安全,並幫助編譯服務器隨時隨地處理任何輸入錯誤。

要回到關鍵點,您嘗試執行的操作最好通過使用maps和typedefs來實現。地圖可讓您存儲正確的鍵值對(通過方法和括號表示法),而typedefs讓您鍵入數據結構,確保類型安全。

考慮到這一點,您的代碼段可以被重新創建如下:

class Test { 
    static var data : Map<String, Room> = new Map<String, Room>(); 

    static function main() { 
     data["R100"] = { monsterCount: 5 }; 
     data["R200"] = { monsterCount: 10 }; 

     trace(data["R100"].monsterCount); 
     trace(data["R200"].monsterCount); 
    } 
} 

typedef Room = { 
    var monsterCount : Int; 
} 

Room現在是由{ "monsterCount": (Int) }數據結構所描述的類型,並且被映射到字符串鍵,其表示房間ID。

Map API允許您設置和刪除地圖中的鍵值對,以及迭代鍵/值等等。請務必查看API docs瞭解更多信息。通過lordkryss提供


編輯(2016年7月26日)

答案是完全有效的。不過,有兩個主要原因,我沒有提出reflection

  • 反射是一種運行時功能,它的使用會不必要地使您的代碼複雜化,並且不提供所需的語法。
  • 反射在不同的目標上可能是昂貴和不可預測的。

一般來說,你應該用車費反射動態更好,而不是靜態目標。在開發您的項目並確定您的目標平臺將是什麼時請記住這一點。

我建議考慮產生的來源,以更好地瞭解反射的影響。您可以使用官方的try.haxe.org沙盒來查看Haxe 3.2.0生成的JavaScript源代碼。還有unofficial sandbox,它也讓你看到Haxe 3.3.0-rc.1生成的JavaScript源代碼。

個人而言,我不認爲反射是一個可接受的解決方案,您的問題。我發現你的問題是找到合適的數據結構來表示你的數據。反射有其用處,但我不會在這種情況下推薦它。

2

雖然Domagoj的解決方案可能是一個更好的解決你的問題,你實際上可以做你的問題問什麼用Reflection

class Test { 
    static public var data = 
    { 
     room: { 
      "R100": {monstersLeft: 2 } 
     } 
    } 



    static function main() { 
     var newRoom = "R200"; 
     Reflect.setField(data,newRoom,{monstersLeft:5}); 
     trace(Reflect.getProperty(data, newRoom).monstersLeft); 
    } 
} 

您可以在try.haxe.org

+0

謝謝你們,所有這些答案都是偉大的。我現在已經和LordKryss一起回答了,只是因爲它是最容易實現的,但是當我運行它時,會回頭看看正確的結構。謝謝大家 – Ferrari177

3

嘗試代碼考慮使用haxe.DynamicAccess它是Reflect的編譯時包裝器。所以它不會增加任何運行時開銷,但給操作匿名結構提供了方便的語法。

import haxe.DynamicAccess; 

typedef TRoom = { 
    monstersLeft : Int 
} 


class Test { 
    static public var data : {room:DynamicAccess<TRoom>} = { 
     room: { 
      "R100": {monstersLeft: 2} 
     } 
    }; 


    static function main() { 

     var newRoom = "R200"; 
     data.room[newRoom] = {monstersLeft:10}; 

     trace(data.room['R200'].monstersLeft); 
    } 
} 

你可以在這裏嘗試一下:http://try.haxe.org/#cBc45

+0

我不相信這是編譯時間,所有反射都是在運行時完成的。爲了編譯時間模擬可能看起來像反射的東西,你需要使用宏。 – Chii

+0

我在反射之上沒有額外的開銷。 – RealyUniqueName

0

您也可以使用這個StringMap,因爲這是你想要的:)一個地圖應當建立這樣的:[key => value, key => value ..]。請注意,你有array access這種類型的地圖,它給你你要求的語法。

class Test { 
    static public var data = { 
     rooms: [ 
      "R100" => {monstersLeft: 2} 
     ] 
    } 

    static function main() { 
     // add room 
     data.rooms["R200"] = {monstersLeft: 5}; 

     // read room 
     trace(data.rooms["R100"].monstersLeft); // 2 
    } 
} 

演示:http://try.haxe.org/#2B855

這不是真正的問題,但要避免反射完全可以使用數組而不是對象。這是一個架構改變,使用它的選擇主要取決於你想通過其ID來搜索房間的多少。如果這很常見,那麼使用地圖,否則可以考慮這一點。

class Test { 
    static public var data = { 
     rooms: [ 
      {id:"R100", monstersLeft: 2}, 
     ] 
    } 

    static function main() { 
     // add room 
     var newRoom = {id:"R200", monstersLeft: 5}; 
     data.rooms.push(newRoom); 

     // find rooms 
     var room100 = findRoom("R100"); 
     trace(room100.monstersLeft); // 2 
    } 

    static function findRoom(id:String) { 
     for (room in data.rooms) if (room.id == id) return room; 
     return null; 
    } 
} 

演示:http://try.haxe.org/#8bFfD