80

Rust has the unit type, (), a type with a single zero-size value. The value of this unit type is also specified using ().

What is the purpose of the unit type and its value? Is it a mechanism to avoid using null (or nil) like other languages have?

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
Will
  • 1,413
  • 1
  • 15
  • 13
  • 6
    It's more like `void` in C-like languages. As far as I know, everything is an expression in rust, so `()` is the value returned by something which is only executed for its effects. – Lee Jul 19 '14 at 16:28
  • 1
    You can make your own zero-size types, just like `()` by saying `struct MyNewZeroSizeType;` It can be useful ("marker types"!) – bluss Jul 19 '14 at 18:18
  • 2
    It's doesn't seem like `null` in java because if you say your returning an `int` you can't return `()` in place of it. – JustGage Sep 27 '14 at 06:03

3 Answers3

105

() is a value of the type () and its purpose is to be useless.

Everything in Rust is an expression, and expressions that return "nothing" actually return (). The compiler will give an error if you have a function without a return type but return something other than () anyway. For example

fn f() {
    1i32 // error: mismatched types: expected `()` but found `int`
}

There are practical uses for () too. Sometimes we don't care about a generic type, and () makes this explicit.

For example, a Result<(), String> can be used as return type for a function that either completes successfully or fails for a variety of reasons.

hellow
  • 12,430
  • 7
  • 56
  • 79
A.B.
  • 15,364
  • 3
  • 61
  • 64
  • In suppose one can also define methods for it, but there will be no state associated with those... Is that correct? – errordeveloper Jul 19 '14 at 22:53
  • 1
    @errordeveloper yes, pretty much everything you can do with `()` has a trivial implementation. – huon Jul 20 '14 at 00:17
50

If you're coming from a C-like language (C, C++, Java, etc.), you can think of unit as being like void. It is the type you return when you don't want to return anything.

Type theorists will point out that unit is not like void, because unit has exactly 1 value whereas void has 0 values.

In practice, the amount of information you can store in both types is the same (0 bits), although languages that use unit tend to be nicer to work with because you can treat it as you would any other value.

You can store it in a variable, struct, collection, or anywhere else you could store a value. You can pass as an argument or return it as a result. You can create a reference to it. Etc.

So, when is that useful? Mainly when you don't care what type of value you're dealing with. It means you can write polymorphic/generic code without needing to worry about whether the value you are dealing with actually contains any information, that is, no need of a special case for whether you're storing actual data or ().

One example of where this is used is in HashSet. A HashSet<T> is actually implemented as a thin wrapper around HashMap<T, ()>. (A map from the generic type T to ())

nbro
  • 15,395
  • 32
  • 113
  • 196
aij
  • 5,903
  • 3
  • 37
  • 41
  • 1
    another area of use is in Dynamic Dispatch where the TraitObject implementation documented [here](https://doc.rust-lang.org/1.30.0/std/raw/struct.TraitObject.html) has the `*mut ()` type for data and vtable. – Sid Jan 25 '19 at 13:13
  • 4
    I'd add that `void` and `()` are also very useful not just when you don't care about the result, but when there _is_ no result. I might have a method which stores to a file and either fails with an error or just completes successfully with no further information -- `Result<(), MyError>`. You could argue that `Option` is 'better', but I disagree; the `Result`'s naming conventions mean it's explicitly clear what's going on. – Nic Mar 10 '19 at 17:42
0

Unit type () is used when you have code that does not return anything. from the docs

The () type, also called “unit”.

The () type has exactly one value (), and is used when there is no other meaningful value that could be returned.

1- function that is not returning anything

fn test()->() {}

2- code block that does not return anything:

// in this case type will be let x:()={codeblock}
let x={
        println!("testing code block")
    };
  • since each unit type has exactly one value, all unit type variables are equal. for example

    fn main(){
       let x=();
       let y=println!("test");
       // this will print out true
       println!("Are x and y variables equal? / {}",x==y);
    }
    

3- it is commonly used in Result enum where you are not returning anything but want to write type for successful execution. example from docs:

use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
    let greeting_file = File::open("hello.txt")?;

    Ok(())
}
Yilmaz
  • 35,338
  • 10
  • 157
  • 202