Global mutable variables in Rust

  1. Background:

I want to create an app using Tauri. It allows you to create app with html/JS frontend and Rust backend.

For communicating between frontend and backend, you can create tauri-commands using #[tauri::command] macro. This allows you to create functions that can be called in the frontend.

I was trying to implement the game-of-life in rust and display it using tauri.

  1. Game Implementation Overview:

I have declared the game struct

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
    Dead = 0,
    Alive = 1,

pub struct Universe {
    width: u32,
    height: u32,
    cells: Vec<Cell>,

There are three functions that are important:

impl Universe {
  pub fn new() -> Universe // for creating the Game object
  pub fn render(&self) -> String // for getting the game state as string, so that it can be rendered on the fronend. 
  pub fn tick(&mut self) // For changing the cell to the next state
  1. Problems I am facing

I want to create two tauri-commands

fn get_game_state() -> String

fn tick_game() 

The problem is that I cannot pass the game object to these functions as a parameter. So I thought of creating a global game object. Rust was giving error with this, so I used an external crate: lazy_static to initialize the global game object.

lazy_static! {
    static ref GAME: Universe = {
        let mut game = Universe::new();

Now I'm implementing the tauri-commands as follows:

fn get_game_state() -> String {

fn tick_game() {

However, the rust compiler is giving the following error:
error[E0596]: cannot borrow data in dereference of GAMEas mutable

30 |     GAME.tick();
   |     ^^^^^^^^^^^ cannot borrow as mutable

How do I fix this error ?. Also, is there a better way to manage my game state instead of using global variable. ?

Looks like you might need a RwLock around your global state. This can hand out mutable or immutable locks so your state can only be modified in one place at a time.


You can wrap it in a Mutex or an RwLock like @tuffy said ( playground ):

lazy_static! {
    static ref GAME: Mutex<Universe> = {
        let game = Universe::new();

fn main() {

This means that every modification to GAME will be required to make sure it is either the only one using it ( with a Mutex ) or that it follows the Rust borrowing rules of many readers or one writer ( with an RwLock ).

1 Like

Hey, we use Tauri for an application at work!

You should use Builder::manage() to tell Tauri to manage a piece of state and make it accessible to your commands later on. All you'll need to do is add a universe: tauri::State<Universe> argument to your command function.

I'll copy the example here:

use std::{collections::HashMap, sync::Mutex};
use tauri::State;
// here we use Mutex to achieve interior mutability
struct Storage {
  store: Mutex<HashMap<u64, String>>,
struct Connection;
struct DbConnection {
  db: Mutex<Option<Connection>>,

fn connect(connection: State<DbConnection>) {
  // initialize the connection, mutating the state with interior mutability
  *connection.db.lock().unwrap() = Some(Connection {});

fn storage_insert(key: u64, value: String, storage: State<Storage>) {
  // mutate the storage behind the Mutex, value);

  .manage(Storage { store: Default::default() })
  .manage(DbConnection { db: Default::default() })
  .invoke_handler(tauri::generate_handler![connect, storage_insert])
  // on an actual app, remove the string argument
  .expect("error while running tauri application");

Global variables really hurt you in the long run because it makes it hard to manage access to the state, and their singleton nature makes testing quite difficult.


Ooh, that's a nice solution! I used Tauri a while back now, it looks like it's gotten some upgrades. :slight_smile: And they've gotten 1.0 out now!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.