Structs & impl β Ruby's class Splits Into Two Pieces in Rust
struct for data, impl for methods, trait for polymorphism
In Ruby, a class bundles data (instance variables) and methods together. Rust separates them.
# Ruby β data and methods in one body
class User
attr_reader :name, :email
def initialize(name, email)
@name = name
@email = email
end
def display
"#{name} <#{email}>"
end
end
// Rust β data
struct User {
name: String,
email: String,
}
// Rust β methods (separate block)
impl User {
fn new(name: String, email: String) -> Self {
User { name, email }
}
fn display(&self) -> String {
format!("{} <{}>", self.name, self.email)
}
}
&self β Ruby's implicit self made explicit
In Ruby, self is automatic inside instance methods. Just name works as self.name. In Rust, you must explicitly pass &self as the first argument.
&selfβ read-only (like Ruby's normal methods)&mut selfβ can modify (like Ruby's!methods)selfβ takes ownership (original unusable after call)
impl User {
fn name(&self) -> &str { &self.name } // read
fn set_name(&mut self, name: String) { self.name = name; } // write
fn into_name(self) -> String { self.name } // ownership move
}
Associated functions β Ruby's class methods
Functions without &self are Ruby's class methods.
# Ruby
User.create(name: "sehwa") # class method
// Rust
User::new(String::from("sehwa"), String::from("s@e.com")); // called with ::
:: instead of .. new isn't a keyword β just convention.
trait β Ruby's module
Like Ruby's include mixes in modules, Rust impls traits.
# Ruby
module Printable
def print_info
puts to_s
end
end
class User
include Printable
end
// Rust
trait Printable {
fn print_info(&self);
}
impl Printable for User {
fn print_info(&self) {
println!("{}", self.display());
}
}
Key difference: Ruby modules can include implementations and allow free multiple inclusion. Rust traits are closer to interfaces, with implementations in impl Trait for Type. No diamond inheritance problem.
derive β automatic implementation
In Ruby, including Comparable and defining <=> gives you all comparison operators for free. Rust's derive is similar.
#[derive(Debug, Clone, PartialEq)]
struct User {
name: String,
email: String,
}
Debug is like puts user.inspect, Clone is .dup, PartialEq is ==. One annotation line, auto-implemented.
No inheritance
Rust has no inheritance. This is the biggest paradigm shift for Ruby developers. Code reuse happens through composition (putting structs inside structs) or traits.
Key Points
Define data with struct, methods with impl β separate blocks
&self = read, &mut self = write, self = ownership move
trait maps to Ruby module include β used instead of inheritance
derive auto-implements Debug, Clone, PartialEq etc.
Pros
- ✓ Data and behavior separation makes structure clear
- ✓ Traits have no diamond inheritance problem
Cons
- ✗ Ruby's open class (adding methods to existing classes) isn't possible
- ✗ Mindset shift needed for code reuse without inheritance