1

I'm searching an easy, not bloated solution for an easy problem.

Code (playpen):

use std::ops::Range;

// Sum of square numbers from 1 to 10 # 1^2 + 2^2 + 3^2 ...
fn sum_square(v: &[i64; 10]) -> i64 {
    let mut sum: i64 = 0;
    for x in v {
        sum += x * x;
    }
    return sum;
}


// Square sum of the added numbers from 1 to 10 # (1+2+3+...)^2
fn square_sum(v: &[i64; 10]) -> i64{
    let mut sum: i64 = 0;
    for x in v {
        sum += x;
    }
    return sum*sum;
}

fn main() {
    let v: [i64; 10] = [1,2,3,4,5,6,7,8,9,10];
    let diff = sum_square(&v) - square_sum(&v);
    println!("{}", diff);
}

I have an array in the main function, filled with numbers from 1-10 (yes I know [1..11] doesn't work, but what's the best solution? Using "range" is out of question, I want an array without having to type each number). Now I need to iterate over this array multiple times (here 2x) in different functions.

I don't want to use .copy() (because I don't want to move), I want to borrow the array to the functions like explained here: https://i.stack.imgur.com/VlZ8N.jpg

fn main() {
    let v: [i64; 10] = [1..11];
    let diff = sum_square(&v) - square_sum(&v);
    println!("{}", diff);
}

Two functions, each iterating over this array. So I just use a

fn sum_square(v: &[i64; 10]) -> i64 {
    let mut sum: i64 = 0;
    for x in v {
        sum += x * x;
    }
    return sum;
}

Seems to work. If I use the second function

// Square sum of the added numbers from 1 to 10 # (1+2+3+...)^2
fn square_sum(v: &[i64; 10]) -> i64{
    let mut sum: i64 = 0;
    for x in v {
    sum += x;
    }
    return sum*sum;
}

I get an error: type mismatch resolving <core::slice::Iter<'_, i64> as core::iter::Iterator>::Item == i64:

Chris Morgan
  • 86,207
  • 24
  • 208
  • 215
Vega
  • 2,661
  • 5
  • 24
  • 49
  • Please include the code in the question; a playpen link in addition is OK, but not by itself. (I can't fix it right now as I can't select the code on a mobile device in playpen to paste it here.) – Chris Morgan Feb 28 '15 at 08:01
  • Will do in my next question, got it sorted out with the explanation fom Pothead and Shepmaster (Code in the comment of Potheads explanation). Would post the code in the comment here but without code formatting that would get really messy :(. – Vega Feb 28 '15 at 12:53

2 Answers2

2

Pothead Grandma has a reasonable explanation, but I wanted to also include some other details.

fn square_sum(v: &[i64]) -> i64 { // 1
    let mut sum = 0;
    for &x in v { // 2
        sum += x;
    }
    sum * sum // 3
}

fn main() {
    let v: Vec<_> = (1..11).collect(); // 4
    let diff = sum_square(&v) - square_sum(&v); //5
    println!("{}", diff);
}
  1. We accept a slice of numbers, instead of a reference to an array. A slice is just a chunk of values and how many values there are.
  2. We bind to a reference variable, so x will be implicitly dereferenced. This means that instead of having to always say *x to get to the value of the variable, we can use x to get to the value.
  3. No need for an explicit return statement. Explicit returns are useful when you return early from a method, but if a function returns a value, then the last statement of the function is the return value.
  4. Use a range and collect it into a Vec. collect takes an iterator and makes a collection (in this case a Vec).
  5. We take a reference to the Vec. Rust has auto-dereferencing rules, and &Vec<T> will dereference to &[T].

In the spirit of showing a more Rust-like way of solving this problem, I'll also show fold and map:

fn sum_square(v: &[i64]) -> i64 {
    v.iter().map(|i| i * i).fold(0, |accumulator, i| accumulator + i)
}

fn square_sum(v: &[i64]) -> i64 {
    let sum = v.iter().fold(0, |accumulator, &i| accumulator + i);
    sum * sum
}

Or using AdditiveIterator:

use std::iter::AdditiveIterator;

fn sum_square(v: &[i64]) -> i64 {
    v.iter().map(|i| i * i).sum()
}

fn square_sum(v: &[i64]) -> i64 {
    let sum: i64 = v.iter().cloned().sum();
    sum * sum
}
Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I thought &v would be the reference to the array v? Now I'm confused. To 2. I'm not sure I understand that 100%. To 3. - I like explicit return statements, makes it easier to spot where I return values. 4. just what I searched, thanks :). – Vega Feb 28 '15 at 00:36
  • @Vega In my code, `v` is no longer an *array* - it's a *slice*. Arrays have a length set at *compile-time*, while slices are determined at *runtime*. I tried to add some more detail as well. – Shepmaster Feb 28 '15 at 00:46
1

I'm new to Rust myself so my explanation might be incorrect or outdated, but it looks like that the issue is caused by a type mismatch.

fn sum_square(v: &[i64; 10]) -> i64 {
    let mut sum: i64 = 0;
    for x in v {
        sum += x * x;
    }
    return sum;
}

Here x has type &i64. It is a reference to the value inside the array. Multiplying or applying any other operator on x causes it to dereference - i.e. x*x now has type i64.

fn square_sum(v: &[i64; 10]) -> i64{
    let mut sum: i64 = 0;
    for x in v {
        sum += x;
    }
    return sum*sum;
}

Here x also has type &i64, but this time it won't get dereferenced. A correct solution would look like this:

fn square_sum(v: &[i64; 10]) -> i64{
    let mut sum: i64 = 0;
    for x in v {
        // alternatively sum = x + sum works, but sum = sum + x doesn't.
        sum += *x;
    }
    return sum*sum;
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • That .... makes sense. Got the array thing sorted out, running code under: http://is.gd/QkZapx. Thanks :). – Vega Feb 28 '15 at 00:33
  • Commented code so that I don't forget why I need to dereference in the second loop: http://is.gd/Yqf32x – Vega Feb 28 '15 at 00:45