代码之家  ›  专栏  ›  技术社区  ›  StackedCrooked

在Clojure中使用C风格的封装技术?

  •  3
  • StackedCrooked  · 技术社区  · 14 年前

    Clojure program 我真的对我如何在全球范围内宣布我所有的可变状态感到不舒服。例如:

    (def next-blocks (atom []))
    (def num-next-blocks 1)
    (def is-game-over (atom false))
    (def user-name (atom (str)))
    (def hs-xml (atom nil))
    

    因为我在工作中经常使用C,所以我想到了使用普通C风格的封装技术。它通常涉及作为第一个参数传递给对其进行操作的任何“成员函数”的struct对象。看到了吗 udev

    (defstruct gamestate)
    
    (defn game-new []
      (struct-map gamestate
        :level            (atom 0)
        :score            (atom 0)
        ;etc...
        ))
    
    (def game-get-score [game]
        @(game :score))
    
    (defn game-set-score [game new-score]
      (reset! (game :score) new-score))
    
    (defn game-get-level [game]
      @(game :level))
    
    (defn game-inc-level [game]
      (swap! (game :level) inc))
    
    ; etc...
    

    所以这是推荐的方法吗?还是有更标准的Clojure方式?

    我目前正在使用Clojure 1.1.0。

    3 回复  |  直到 14 年前
        1
  •  6
  •   Adam Schmideg    14 年前

    函数式编程的基本思想是只有很少的全局变量,而大部分是局部变量(参见 Rich Hickey's article on state and identity this post on functional programming for games (不过,例子是在Erlang中)。

    我不知道你想玩什么游戏。下面是一个代码片段,我将如何处理局部变量。

    (defn play-game [name score blocks]
      (let [level (start-mission (:level score) blocks)]
        (if level
          (assoc score :level level)
          score)))
    
    (defn the-whole-game []
      (let [name (ask-username)
            score (or (load-score name) {:level 0, :score 0}]
        (when-let [new-score (play-game name score [])]
           (save-score name new-score))))
    

    你可能想退房 another Tetris clone in clojure

        2
  •  4
  •   mikera    14 年前

    在我的Clojure游戏中,我使用一个包含一个映射的原子来存储我所有可变的游戏状态。这包括用户界面状态的某些元素。

    目前定义如下:

    (def state 
      (atom 
        {:game (gamefactory/make-game)
         :scroll [0 0]
         :mouseover [0 0]
         :command-state nil
         :commands (clojure.lang.PersistentQueue/EMPTY)
         :animations {}
         :player-id nil}))
    

    这个模型对我很适用。您可以轻松地直接访问state元素,例如(:game@state),或者定义访问器函数。

        3
  •  2
  •   sjagr    14 年前

    可以使用映射来模拟C样式的结构。您还可以使用deftype/defrecord(如果您使用的是v1.2)。

    (defn get-game-score [game]
       (:score game))
    
    (defn set-game-store [game new-score]
       (assoc game :score new-score))
    

    我建议使用地图,特别是因为这些可以很容易地用于多种方法。
    要记住的最大的一点是,你不应该像在C语言中那样考虑在clojure中使用变量,原子和变量是不一样的。