es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Gestionando el estado global desde una biblioteca

Estoy escribiendo una biblioteca en Rust que implementa una cierta estructura y sus métodos. Sin embargo, quiero exponer al consumidor solo los métodos y dejar ocultas las variables de estado, solo exponiendo algunas a través de funciones de obtención. A modo de ejemplo del tipo de comportamiento que deseo, aquí hay un fragmento en C:

// library.h
void init();
void do_stuff();
int get();

// library.c
typedef struct State {
  int a, b;
} State;

State G_STATE;

void init() {} // Inicializa G_STATE
void do_stuff() {} // Lógica con G_STATE
int get() { return G_STATE.a; } // Devuelve solo una parte de G_STATE

// main.c

#include <stdio.h>
#include "library.h"

int main() {
  init();
  do_stuff();
  printf(get());
  return 0;
}

Esto claramente no es seguro y todo eso, pero es suficiente para describir el comportamiento. ¿Existe una forma idiomática en Rust para obtener este estilo de API? ¿Una forma que, tal vez, tampoco tenga las mismas deficiencias que el fragmento anterior en cuanto a la seguridad de la memoria y los tiempos de vida indefinidos de las variables globales?</stdio.h>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Sí, la forma idiomática de lograr este comportamiento en Rust es utilizar la encapsulación e implementar la estructura como un módulo privado.

    Primero, define un módulo para la estructura y sus métodos:

    mod my_struct {
        struct MyStruct {
            a: i32,
            b: i32,
        }
    
        impl MyStruct {
            pub fn new() -> Self {
                MyStruct { a: 0, b: 0 }
            }
    
            pub fn do_stuff(&mut self) {
                // Lógica con self.a y self.b
            }
    
            pub fn get_a(&self) -> i32 {
                self.a
            }
        }
    }
    

    Luego, en el módulo público, crea funciones envolventes que utilizan el módulo privado:

    mod public_module {
        use super::my_struct::MyStruct;
    
        pub fn init() -> MyStruct {
            MyStruct::new()
        }
    
        pub fn do_stuff(s: &mut MyStruct) {
            s.do_stuff();
        }
    
        pub fn get() -> i32 {
            let s = init();
            s.get_a()
        }
    }
    

    De esta manera, el consumidor solo puede acceder a las funciones init(), do_stuff() y get(), y ninguna de las variables de estado está expuesta. La estructura en sí solo es accesible dentro del módulo privado my_struct.

Comments are closed.