Skip to main content

Getting a Value

Now that we have created and initialized a storage value, we are going to start to interact with it!

Contract Functions

As you can see in the contract template, all of your contract functions are part of your contract module.

impl MyContract {
// Public and Private functions can go here
}

Public and Private Functions

In Rust, you can make as many implementations as you want. As a stylistic choice, we recommend breaking up your implementation definitions for your private and public functions:

impl MyContract {
/// Public function
#[ink(message)]
pub fn my_public_function(&self) {
/* --snip-- */
}

/// Private function
fn my_private_function(&self) {
/* --snip-- */
}

/* --snip-- */
}

You can also choose to split things up however is most clear for your project.

Note that all public functions must use the #[ink(message)] attribute.

Storage Value API

Without going into so much detail, storage values are a part of the underlying ink! core layer. In the background, they use a more primitive cell type which holds an Option<T>. When we try to get the value from storage, we unwrap the value, which is why it panics if it is not initialized!

impl<T> Value<T>
where
T: scale::Codec,
{
/// Returns an immutable reference to the wrapped value.
pub fn get(&self) -> &T {
self.cell.get().unwrap()
}

/// Returns a mutable reference to the wrapped value.
pub fn get_mut(&mut self) -> &mut T {
self.cell.get_mut().unwrap()
}

/// Sets the wrapped value to the given value.
pub fn set(&mut self, val: T) {
self.cell.set(val);
}
}

In that same file, you can find the other APIs exposed by storage values, however these three are the most commonly used.

Getting a Value

We already showed you how to initialize a storage value. Getting the value is just as simple:

impl MyContract {
#[ink(message)]
fn my_getter(&self) -> u32 {
self.number
}
}

In Rust, if the last expression in a function does not have a semicolon, then it will be the return value.

Your Turn!

Follow the ACTIONs on the code template provided.

Remember to run cargo +nightly test to test your work.

#![cfg_attr(not(feature = "std"), no_std)]

use ink_lang as ink;

#[ink::contract]
mod incrementer {

#[ink(storage)]
pub struct Incrementer {
value: i32,
}

impl Incrementer {
#[ink(constructor)]
pub fn new(init_value: i32) -> Self {
Self {
value: init_value
}
}

#[ink(constructor)]
pub fn default() -> Self {
Self {
value: 0
}
}

#[ink(message)]
// ACTION: Update this function to return an i32.
pub fn get(&self) {
// ACTION: Return the `value`.
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn default_works() {
let contract = Incrementer::default();
assert_eq!(contract.get(), 0);
}
}
}