Why cant a static hashmap for a memoizing function be borrowed as mutable?










2















I'm trying to create a memoization function in Rust. The problem comes when getting a mutable reference for the cache HashMap. I'm not still confident with the type system and I'm struggling a bit.



use std::collections::HashMap;
use std::hash::Hash;

fn memoize<A, B, F>(f: F, cache: &'static HashMap<A, B>) -> impl Fn(A) -> B
where
A: Eq + Hash + Copy,
B: Clone,
F: Fn(A) -> B,

if !cache.contains_key(&value)
cache.insert(value, f(value.clone()));

let res = cache.get(&value).unwrap();
res.clone()




The error is:



error[E0596]: cannot borrow immutable borrowed content `**cache` as mutable
--> src/lib.rs:12:13
|
12 | cache.insert(value, f(value.clone()));
| ^^^^^ cannot borrow as mutable


Why cannot a static lifetime parameter be mutable?










share|improve this question




























    2















    I'm trying to create a memoization function in Rust. The problem comes when getting a mutable reference for the cache HashMap. I'm not still confident with the type system and I'm struggling a bit.



    use std::collections::HashMap;
    use std::hash::Hash;

    fn memoize<A, B, F>(f: F, cache: &'static HashMap<A, B>) -> impl Fn(A) -> B
    where
    A: Eq + Hash + Copy,
    B: Clone,
    F: Fn(A) -> B,

    if !cache.contains_key(&value)
    cache.insert(value, f(value.clone()));

    let res = cache.get(&value).unwrap();
    res.clone()




    The error is:



    error[E0596]: cannot borrow immutable borrowed content `**cache` as mutable
    --> src/lib.rs:12:13
    |
    12 | cache.insert(value, f(value.clone()));
    | ^^^^^ cannot borrow as mutable


    Why cannot a static lifetime parameter be mutable?










    share|improve this question


























      2












      2








      2








      I'm trying to create a memoization function in Rust. The problem comes when getting a mutable reference for the cache HashMap. I'm not still confident with the type system and I'm struggling a bit.



      use std::collections::HashMap;
      use std::hash::Hash;

      fn memoize<A, B, F>(f: F, cache: &'static HashMap<A, B>) -> impl Fn(A) -> B
      where
      A: Eq + Hash + Copy,
      B: Clone,
      F: Fn(A) -> B,

      if !cache.contains_key(&value)
      cache.insert(value, f(value.clone()));

      let res = cache.get(&value).unwrap();
      res.clone()




      The error is:



      error[E0596]: cannot borrow immutable borrowed content `**cache` as mutable
      --> src/lib.rs:12:13
      |
      12 | cache.insert(value, f(value.clone()));
      | ^^^^^ cannot borrow as mutable


      Why cannot a static lifetime parameter be mutable?










      share|improve this question
















      I'm trying to create a memoization function in Rust. The problem comes when getting a mutable reference for the cache HashMap. I'm not still confident with the type system and I'm struggling a bit.



      use std::collections::HashMap;
      use std::hash::Hash;

      fn memoize<A, B, F>(f: F, cache: &'static HashMap<A, B>) -> impl Fn(A) -> B
      where
      A: Eq + Hash + Copy,
      B: Clone,
      F: Fn(A) -> B,

      if !cache.contains_key(&value)
      cache.insert(value, f(value.clone()));

      let res = cache.get(&value).unwrap();
      res.clone()




      The error is:



      error[E0596]: cannot borrow immutable borrowed content `**cache` as mutable
      --> src/lib.rs:12:13
      |
      12 | cache.insert(value, f(value.clone()));
      | ^^^^^ cannot borrow as mutable


      Why cannot a static lifetime parameter be mutable?







      static rust lifetime mutable






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 15 '18 at 15:33









      Shepmaster

      157k14316457




      157k14316457










      asked Nov 14 '18 at 9:44









      NetwaveNetwave

      12.7k22145




      12.7k22145






















          1 Answer
          1






          active

          oldest

          votes


















          4














          A variable is immutable by default in Rust, therefore you cannot mutate a variable that is not declared as mut. The 'static lifetime does not influence the mutability, but only how long the variable lives.



          A Fn "[...] can be called repeatedly without mutating state.". And exactly here is the problem. You want to mutate the environment (in this case your HashMap).



          You have to use a FnMut to be able to mutate the environment.



          If you use the Entry API, you can simplify your code:



          use std::collections::HashMap;
          use std::hash::Hash;

          fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
          where
          A: Eq + Hash + Copy,
          B: Clone,
          F: Fn(A) -> B,

          let res = cache.entry(value).or_insert_with(



          As a sidenote, if you compile your code with #[feature(nll)] the error message is actually very good.



          error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
          --> src/lib.rs:14:13
          |
          14 | cache.insert(value, f(value.clone()));
          | ^^^^^ cannot borrow as mutable
          |
          help: consider changing this to accept closures that implement `FnMut`





          share|improve this answer

























          • Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

            – Netwave
            Nov 14 '18 at 9:57






          • 1





            @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

            – hellow
            Nov 14 '18 at 10:23











          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297128%2fwhy-cant-a-static-hashmap-for-a-memoizing-function-be-borrowed-as-mutable%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          4














          A variable is immutable by default in Rust, therefore you cannot mutate a variable that is not declared as mut. The 'static lifetime does not influence the mutability, but only how long the variable lives.



          A Fn "[...] can be called repeatedly without mutating state.". And exactly here is the problem. You want to mutate the environment (in this case your HashMap).



          You have to use a FnMut to be able to mutate the environment.



          If you use the Entry API, you can simplify your code:



          use std::collections::HashMap;
          use std::hash::Hash;

          fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
          where
          A: Eq + Hash + Copy,
          B: Clone,
          F: Fn(A) -> B,

          let res = cache.entry(value).or_insert_with(



          As a sidenote, if you compile your code with #[feature(nll)] the error message is actually very good.



          error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
          --> src/lib.rs:14:13
          |
          14 | cache.insert(value, f(value.clone()));
          | ^^^^^ cannot borrow as mutable
          |
          help: consider changing this to accept closures that implement `FnMut`





          share|improve this answer

























          • Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

            – Netwave
            Nov 14 '18 at 9:57






          • 1





            @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

            – hellow
            Nov 14 '18 at 10:23
















          4














          A variable is immutable by default in Rust, therefore you cannot mutate a variable that is not declared as mut. The 'static lifetime does not influence the mutability, but only how long the variable lives.



          A Fn "[...] can be called repeatedly without mutating state.". And exactly here is the problem. You want to mutate the environment (in this case your HashMap).



          You have to use a FnMut to be able to mutate the environment.



          If you use the Entry API, you can simplify your code:



          use std::collections::HashMap;
          use std::hash::Hash;

          fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
          where
          A: Eq + Hash + Copy,
          B: Clone,
          F: Fn(A) -> B,

          let res = cache.entry(value).or_insert_with(



          As a sidenote, if you compile your code with #[feature(nll)] the error message is actually very good.



          error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
          --> src/lib.rs:14:13
          |
          14 | cache.insert(value, f(value.clone()));
          | ^^^^^ cannot borrow as mutable
          |
          help: consider changing this to accept closures that implement `FnMut`





          share|improve this answer

























          • Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

            – Netwave
            Nov 14 '18 at 9:57






          • 1





            @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

            – hellow
            Nov 14 '18 at 10:23














          4












          4








          4







          A variable is immutable by default in Rust, therefore you cannot mutate a variable that is not declared as mut. The 'static lifetime does not influence the mutability, but only how long the variable lives.



          A Fn "[...] can be called repeatedly without mutating state.". And exactly here is the problem. You want to mutate the environment (in this case your HashMap).



          You have to use a FnMut to be able to mutate the environment.



          If you use the Entry API, you can simplify your code:



          use std::collections::HashMap;
          use std::hash::Hash;

          fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
          where
          A: Eq + Hash + Copy,
          B: Clone,
          F: Fn(A) -> B,

          let res = cache.entry(value).or_insert_with(



          As a sidenote, if you compile your code with #[feature(nll)] the error message is actually very good.



          error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
          --> src/lib.rs:14:13
          |
          14 | cache.insert(value, f(value.clone()));
          | ^^^^^ cannot borrow as mutable
          |
          help: consider changing this to accept closures that implement `FnMut`





          share|improve this answer















          A variable is immutable by default in Rust, therefore you cannot mutate a variable that is not declared as mut. The 'static lifetime does not influence the mutability, but only how long the variable lives.



          A Fn "[...] can be called repeatedly without mutating state.". And exactly here is the problem. You want to mutate the environment (in this case your HashMap).



          You have to use a FnMut to be able to mutate the environment.



          If you use the Entry API, you can simplify your code:



          use std::collections::HashMap;
          use std::hash::Hash;

          fn memoize<A, B, F>(f: F, cache: &'static mut HashMap<A, B>) -> impl FnMut(A) -> B
          where
          A: Eq + Hash + Copy,
          B: Clone,
          F: Fn(A) -> B,

          let res = cache.entry(value).or_insert_with(



          As a sidenote, if you compile your code with #[feature(nll)] the error message is actually very good.



          error[E0596]: cannot borrow `*cache` as mutable, as `Fn` closures cannot mutate their captured variables
          --> src/lib.rs:14:13
          |
          14 | cache.insert(value, f(value.clone()));
          | ^^^^^ cannot borrow as mutable
          |
          help: consider changing this to accept closures that implement `FnMut`






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 15 '18 at 15:31









          Shepmaster

          157k14316457




          157k14316457










          answered Nov 14 '18 at 9:55









          hellowhellow

          5,33242242




          5,33242242












          • Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

            – Netwave
            Nov 14 '18 at 9:57






          • 1





            @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

            – hellow
            Nov 14 '18 at 10:23


















          • Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

            – Netwave
            Nov 14 '18 at 9:57






          • 1





            @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

            – hellow
            Nov 14 '18 at 10:23

















          Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

          – Netwave
          Nov 14 '18 at 9:57





          Well, I was pretty close to it. I actually tried the mut modifyer after the static, but even if I read about the FnMut I forgot to use it! Thanks!!

          – Netwave
          Nov 14 '18 at 9:57




          1




          1





          @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

          – hellow
          Nov 14 '18 at 10:23






          @Netwave I optimized the code a litte bit 😸. Of course you can omit res as such and just write .clone() at the end of the first closure line: cache.entry(value).or_insert_with(|| f(value)).clone()

          – hellow
          Nov 14 '18 at 10:23




















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53297128%2fwhy-cant-a-static-hashmap-for-a-memoizing-function-be-borrowed-as-mutable%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Use pre created SQLite database for Android project in kotlin

          Darth Vader #20

          Ondo