Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Rust for Java Devs – Creating Functions

DZone's Guide to

Rust for Java Devs – Creating Functions

Are you a Java developer? Are you also Interested in Rust? We take a look at how to create functions in Rust in a way that makes sense to you Java developers out there.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

In this post of Rust for Java Devs, we will look at creating functions in Rust. Functions in Rust do not differ that much from Java methods, but there are a few little differences. There is also the topic of Rust’s lifetimes compared to Java’s garbage collection that one could argue separates the two from each other a bit more, but for this post, I will focus on the structure of writing a function in Rust. Due to the similarities between the two, I believe most Java developers will have no problem in figuring out what arguments a Rust function takes, what it outputs, and where the output is returned from.

Let's start with a simple method in Java to get us warmed up.

public static void print(final String input) {
    System.out.println("I am printing the value: " + input);
}


There is nothing special about this method. It takes in a String and prints it (along with some other text). It does not return anything, hence the void return type, and it can be publicly accessed due to defining it as public. The method is also static, removing the need for an instance to call it. Note that I have included the final keyword. Although it is pointless for this method, I am trying to bring it closer in line with how Rust works (immutability by default).

Now let's look at the equivalent in Rust.

pub fn print(input: &str) {
    println!("I am printing the value: {}", input)
}


At this point, I would say this is pretty clear for a Java developer — with only one difference that might not be as obvious. We can see that the function is public due to the pub keyword, that the function accepts a String as its only argument, and then goes on to print the input value. One thing that is not included is the return type. That is because this function doesn’t return anything — but unlike the Java version, it does not need to be marked with void. The missing return type is basically an implicit declaration that the method does not return anything.

The return types of Rust’s functions should become clearer after we have gone through the next snippet below.

pub fn add(x: i32, y: i32) -> i32 {
    x + y
}


In this snippet, we have gained an extra bit of code that wasn’t seen in the previous example. The -> i32 that has appeared is declaring it’s return type. The above function is saying that it takes in two i32 numbers and then returns the addition of them also as an i32. The other thing to notice is the missing return keyword that would need to be included in Java.

A bit of background context is required here before I finish explaining the missing return keyword in this Rust function. Rust is comprised of statements and expressions. Statements are instructions that perform an action but do not return a value. Expressions are instructions that evaluate to a value. Therefore, writing 1 + 2 is an expression that evaluates to 3. Hold onto this barely explained concept while we look back at the function above.

A Rust function returns the last expression written in it. This is why we can omit the return keyword — because we can just output the last expression of the function. So if we look back at the earlier snippet, x + y is the last expression. Therefore, its value is computed and returned.

There is one last pitfall we need to cross over regarding the last expression in a function. It cannot have a semicolon at the end of its line. Adding it on prevents the expression from being returned and changes the actual return type of the function to void/no value returned. If we tried to compile the previous function, it won’t build and will print the following compilation error:

error[E0308]: mismatched types
  --> src\main.rs:14:35
   |
14 |   pub fn add(x: i32, y: i32) -> i32 {
   |  ___________________________________^
15 | |   x + y;
   | |        - help: consider removing this semicolon
16 | | }
   | |_^ expected i32, found ()
   |
   = note: expected type `i32`
              found type `()`

error: aborting due to previous error


The error is very helpful and politely asks us to remove the semicolon, although you could consider it impolite, being that the compiler refuses to compile our code. It also shows that rather than the i32 return type that the function says it returns, nothing is returned, as indicated by the found type of ().

Ok, back to looking at the return keyword. If you really wanted to use it in the example, you could, but there is no reason to. The real reason why you still need the return keyword in Rust is to return early from a method, just like you have probably done in Java many times already. For example, if we wanted to write the Rust equivalent of the following Java method:

public static boolean contains(final List<Integer> collection, final int number) {
    for (final int element : collection) {
        if (element == number) {
            return true;
        }
    }
    return false;
}


We would write:

pub fn contains(collection: Vec<i32>, number: i32) -> bool {
    for element in &collection {
        if *element == number {
            return true
        }
    }
    false
}


I am aware that there is some syntax that I haven’t covered that might look alien, but stick with me and just focus on the for loop that iterates through the collection (Vec represents Vector, which is like a Java List) and returns true if the collection contains the input number. To return true early, we need to use the return keyword. It is also worth noting that there, like earlier, is no semicolon on this line, but we could add one if we wanted to, and it would still compile in this situation.

There are a few more points I want to cover in this post, such as function accessibility and static methods, but unfortunately, I believe we first need to go through some other topics before we have all the knowledge required to fully understand them.

I think that, for a first look into Rust functions, we have covered enough to get going, but there is still much more to look into.

In conclusion, Rust functions are not too dissimilar to Java methods. We have seen that both need to define a return type (except for functions that return nothing), though Rust’s void type is implicit, whereas Java’s is explicit. All arguments must be marked with their types. The return keyword is optional on the last expression of a function but still required when returning a value early. Semicolons can be omitted on lines that return values, but are 100% required on a function’s last expression. We have also seen how  we can add pub to a function to make it publicly accessible, but we didn’t look any further into the subject, as I have not covered the required topics that they build upon.

If you found this post helpful and wish to keep up to date with my new tutorials as I write them, follow me on Twitter at @LankyDanDev. You can also contact me here or on twitter if I have made any mistakes while talking about Rust, as I am still in the early days of learning the language and would be grateful for any constructive feedback.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,rust ,functions ,method ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}