Rustã®æææš©ãšåçšïŒå®å šã¬ã€ã
Rustã®æææš©ãšåçšã·ã¹ãã ããã¹ã¿ãŒããŸããæææš©ã«ãŒã«ãåç §ãã©ã€ãã¿ã€ã ãé«åºŠãªã¡ã¢ãªç®¡çãã¿ãŒã³ã解説ããŸãã

æææš©ã·ã¹ãã ã¯ãRustãä»ã®ããããããã°ã©ãã³ã°èšèªãšåºå¥ããç¹åŸŽã§ãããã®ç¬èªã®ã¢ãããŒãã¯ãã¬ããŒãžã³ã¬ã¯ã¿ãªãã§ã¡ã¢ãªå®å šæ§ãä¿èšŒããå®è¡æã§ã¯ãªãã³ã³ãã€ã«æã«ãã°ãæ€åºããŸãããã®è©³çްãªã¬ã€ãã§ã¯ãæææš©ãšåçšã®ã¡ã«ããºã ãåºç€ããæ¬çªç°å¢åãã®é«åºŠãªãã¿ãŒã³ãŸã§è§£èª¬ããŸãã
Rustã³ã³ãã€ã©ã¯å³æ Œãªããã°ã©ãã³ã°ã¢ã·ã¹ã¿ã³ããšããŠæ©èœããŸããã³ã³ãã€ã«æã«ãããã¯ãããæææš©ãšã©ãŒã¯ãæ¬çªç°å¢ã§é²ãããæœåšçãªãã°ãæå³ããŸãã
æææš©ã®3ã€ã®åºæ¬ã«ãŒã«
æææš©ã·ã¹ãã ã¯ãã·ã³ãã«ã§ãããªãã峿 Œãª3ã€ã®ã«ãŒã«ã«åºã¥ããŠããŸãããããã身ã«ã€ããã°ãRustã®ã¡ã³ã¿ã«ã¢ãã«ã¯èªç¶ã§äºæž¬å¯èœãªãã®ã«ãªããŸãã
// Demonstration of the three fundamental rules
fn main() {
// Rule 1: Each value has exactly ONE owner
let s1 = String::from("hello"); // s1 is the sole owner
// Rule 2: There can only be one owner at a time
let s2 = s1; // Ownership transferred (moved) from s1 to s2
// println!("{}", s1); // Compile ERROR: s1 no longer exists
println!("s2 = {}", s2); // Only s2 is valid now
// Rule 3: When the owner goes out of scope, the value is dropped
{
let s3 = String::from("temporary");
println!("s3 inside block = {}", s3);
} // s3 is automatically freed here (drop is called)
// println!("{}", s3); // ERROR: s3 no longer exists
}ããã3ã€ã®ã«ãŒã«ã¯ãuse-after-freeãdouble-freeãã¡ã¢ãªãªãŒã¯ãšãã£ããã°ã®ã«ããŽãªå šäœãæé€ããŸããã³ã³ãã€ã©ã¯ãããã®ã«ãŒã«ãå®ãããŠããããšãéçã«æ€èšŒããŸãã
MoveãšCopyïŒè»¢éã»ãã³ãã£ã¯ã¹ã®çè§£
ä»£å ¥ã®æ¯ãèãã¯ããŒã¿åã«äŸåããŸããCopyãã¬ã€ããå®è£ ããåã¯è€è£œããããã以å€ã®åã¯moveã«ãã£ãŠè»¢éãããŸãã
// Distinction between Copy types and Move types
fn main() {
// Copy types: values stored on the stack, known size
let x: i32 = 42;
let y = x; // x is COPIED, not moved
println!("x = {}, y = {}", x, y); // Both are valid
// Other Copy types: f64, bool, char, tuples of Copy types
let point = (3.0, 4.0);
let point_copy = point; // Tuple copy
println!("Original: {:?}, Copy: {:?}", point, point_copy);
// Move types: values on the heap, dynamic size
let s1 = String::from("owned");
let s2 = s1; // s1 is MOVED to s2
// println!("{}", s1); // ERROR: value moved
println!("s2 = {}", s2);
// Vec, HashMap, Box are also Move types
let vec1 = vec![1, 2, 3];
let vec2 = vec1; // Move, not copy
// println!("{:?}", vec1); // ERROR
println!("vec2 = {:?}", vec2);
}
// Explicit clone to duplicate Move types
fn explicit_clone() {
let original = String::from("important data");
let clone = original.clone(); // Explicit duplication (memory cost)
println!("Original: {}", original); // Still valid
println!("Clone: {}", clone); // Independent copy
}Move/Copyã®åºå¥ã¯åºæ¬çãªãã®ã§ããä»£å ¥ãæææš©ã転éããã®ããç¬ç«ããã³ããŒãäœæããã®ããæ±ºå®ããŸãã
.clone()ã®åŒã³åºãã¯æå³çã§ããã¹ãã§ããcloneã ããã®ã³ãŒãã¯èšèšäžã®åé¡ã瀺ããŠãããããããŸãããåçšãããè¯ã解決çãšãªãããšãå€ãã§ãã
åçšïŒäžå€åç §ãšå¯å€åç §
åçšã«ãããæææš©ãååŸããããšãªãå€ã«ã¢ã¯ã»ã¹ã§ããŸãããã®ã¡ã«ããºã ã«ãããRustã³ãŒãã¯å®å šãã€é«æ§èœã«ãªããŸãã
// Immutable and mutable references
fn main() {
let s = String::from("hello");
// Immutable reference: read-only, multiple allowed
let len = calculate_length(&s); // Immutable borrow
println!("'{}' has {} characters", s, len); // s still valid
// Multiple simultaneous immutable references: OK
let r1 = &s;
let r2 = &s;
let r3 = &s;
println!("r1={}, r2={}, r3={}", r1, r2, r3);
}
fn calculate_length(s: &String) -> usize {
// s is a reference, not the owner
s.len()
} // s goes out of scope but doesn't drop anything (not owner)
// Mutable references: modification allowed
fn mutable_borrowing() {
let mut s = String::from("hello");
change(&mut s); // Mutable borrow
println!("After modification: {}", s);
}
fn change(s: &mut String) {
s.push_str(", world!"); // Modification via mutable reference
}åçšã®é»éã«ãŒã«ïŒè€æ°ã®äžå€åç §ããŸãã¯1ã€ã®å¯å€åç §ã®ããããã§ãããäž¡è ãåæã«ååšããããšã¯æ±ºããŠãããŸããã
ãããŒãã§ãã«ãŒã®ã«ãŒã«
ãããŒãã§ãã«ãŒã¯åçšã«ãŒã«ãæ€èšŒããã³ã³ãã€ã©ã®ã³ã³ããŒãã³ãã§ãããã®ãšã©ãŒãçè§£ããããšã§ãåé¡ãçŽ æ©ã解決ã§ããŸãã
// Strict borrow checker rules
fn main() {
// RULE 1: No mutable reference with immutable references
let mut s = String::from("hello");
let r1 = &s; // Immutable reference: OK
let r2 = &s; // Another immutable reference: OK
// let r3 = &mut s; // ERROR: cannot borrow as mutable
println!("{} and {}", r1, r2);
// AFTER using r1 and r2, they are "dead"
let r3 = &mut s; // Now OK: r1 and r2 no longer used
r3.push_str(" world");
println!("{}", r3);
// RULE 2: Only one mutable reference at a time
let mut data = String::from("exclusive");
let ref1 = &mut data;
// let ref2 = &mut data; // ERROR: already borrowed mutably
ref1.push_str("!");
println!("{}", ref1);
}
// RULE 3: References cannot outlive the data
fn dangling_reference_prevented() {
let reference;
{
let s = String::from("short-lived");
// reference = &s; // ERROR: s doesn't live long enough
}
// s is dropped here, reference would be invalid
// Solution: move the value out of the scope
let owned_outside;
{
let s = String::from("moved out");
owned_outside = s; // Move, not reference
}
println!("{}", owned_outside); // OK: owned_outside is the owner
}ãããŒãã§ãã«ãŒã¯Non-Lexical Lifetimes (NLL)ã䜿çšããŸããåç §ã¯æåŸã«äœ¿çšãããæç¹ãŸã§ã¢ã¯ãã£ããšã¿ãªãããã¹ã³ãŒãã®çµãããŸã§ã§ã¯ãããŸããã
Rustã®é¢æ¥å¯Ÿçã¯ã§ããŠããŸããïŒ
ã€ã³ã¿ã©ã¯ãã£ããªã·ãã¥ã¬ãŒã¿ãŒãflashcardsãæè¡ãã¹ãã§ç·Žç¿ããŸãããã
ã©ã€ãã¿ã€ã ïŒåç §ã®æå¹æéãæ³šéãã
ã©ã€ãã¿ã€ã ã¯ãåç §ãæå¹ã§ããç¶ããããšãã³ã³ãã€ã©ãæ€èšŒããã®ãå©ããæ³šéã§ããã»ãšãã©ã®å Žåãèªåçã«æšè«ãããŸãã
// Explicit lifetime annotations
// Without annotation: compiler infers lifetimes
fn first_word(s: &str) -> &str {
match s.find(' ') {
Some(i) => &s[..i],
None => s,
}
}
// With explicit annotation: same function
fn first_word_explicit<'a>(s: &'a str) -> &'a str {
// 'a means: returned reference lives as long as the input
match s.find(' ') {
Some(i) => &s[..i],
None => s,
}
}
// When annotations are necessary: multiple references
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
// Compiler cannot guess which reference is returned
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("xyz");
result = longest(&string1, &string2);
println!("Longest: {}", result); // OK here
}
// println!("{}", result); // ERROR if uncommented: string2 dropped
}ã©ã€ãã¿ã€ã ã¯ããŒã¿ãçããæéã倿Žãããã®ã§ã¯ãªããç°ãªãåç §ã®ã©ã€ãã¿ã€ã éã®é¢ä¿ãèšè¿°ããŸãã
æ§é äœã«ãããã©ã€ãã¿ã€ã
æ§é äœãåç §ãå«ãå Žåãæ§é äœãåç §å ã®ããŒã¿ããé·ãçåããªãããšãä¿èšŒãããããã©ã€ãã¿ã€ã ãæ³šéããå¿ èŠããããŸãã
// Structs containing references
// Struct with reference: lifetime required
struct ImportantExcerpt<'a> {
part: &'a str, // This reference must live at least as long as the struct
}
impl<'a> ImportantExcerpt<'a> {
// Method returning a reference with the same lifetime
fn level(&self) -> i32 {
3
}
// Elision rule: &self implies the output lifetime
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention: {}", announcement);
self.part // Returns with 'a lifetime from self
}
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().unwrap();
let excerpt = ImportantExcerpt {
part: first_sentence, // OK: novel outlives excerpt
};
println!("Excerpt: {}", excerpt.part);
println!("Level: {}", excerpt.level());
}
// Static lifetime: reference valid for the entire program duration
fn static_lifetime_example() {
let s: &'static str = "This string is in the binary";
// String literals always have 'static lifetime
println!("{}", s);
}ã©ã€ãã¿ã€ã çç¥ã®ã«ãŒã«ã«ãããäžè¬çãªã±ãŒã¹ã§ã¯æ³šéãçç¥ã§ããã³ãŒããèªã¿ããããªããŸãã
é«åºŠãªãã¿ãŒã³ïŒå éšå¯å€æ§
å¯å€æ§ãã³ã³ãã€ã«æã§ã¯ãªãå®è¡æã«æ€èšŒããå¿ èŠãããå ŽåããããŸããRustã¯ãã®ãã¿ãŒã³ã«å¯Ÿå¿ããåãæäŸããŠããŸãïŒRefCellãšCellã§ãã
// Interior mutability with RefCell and Cell
use std::cell::{Cell, RefCell};
// Cell: for Copy types, replaces the entire value
struct Counter {
count: Cell<u32>, // Mutable despite &self
}
impl Counter {
fn new() -> Counter {
Counter { count: Cell::new(0) }
}
fn increment(&self) {
// Modification via immutable reference!
self.count.set(self.count.get() + 1);
}
fn get(&self) -> u32 {
self.count.get()
}
}
// RefCell: for non-Copy types, checks at runtime
struct CachedValue {
value: RefCell<Option<String>>,
}
impl CachedValue {
fn new() -> CachedValue {
CachedValue { value: RefCell::new(None) }
}
fn get_or_compute(&self, compute: impl FnOnce() -> String) -> String {
// borrow() for reading, borrow_mut() for writing
if self.value.borrow().is_none() {
*self.value.borrow_mut() = Some(compute());
}
self.value.borrow().as_ref().unwrap().clone()
}
}
fn main() {
let counter = Counter::new();
counter.increment();
counter.increment();
println!("Counter: {}", counter.get()); // 2
let cache = CachedValue::new();
let result = cache.get_or_compute(|| {
println!("Expensive computation...");
String::from("result")
});
println!("Value: {}", result);
// Second call: no recomputation
let result2 = cache.get_or_compute(|| String::from("never executed"));
println!("Cache hit: {}", result2);
}RefCellãšCellã¯åçšæ€èšŒãå®è¡æã«ç§»ããŸããã«ãŒã«éåã¯ã³ã³ãã€ã«ãšã©ãŒã§ã¯ãªãpanicãåŒãèµ·ãããŸãã
RefCell::borrow_mut()ã¯ãå€ããã§ã«åçšãããŠããå ŽåpanicããŸããæç€ºçãªãšã©ãŒåŠçã«ã¯try_borrow_mut()ã䜿ããšããã§ãããã
ã¹ããŒããã€ã³ã¿ãšæææš©
BoxãRcãArcãªã©ã®ã¹ããŒããã€ã³ã¿ã¯ãç¹å®ã®ãŠãŒã¹ã±ãŒã¹ã«å¯ŸããŠç°ãªãæææš©æŠç¥ãæäŸããŸãã
// Box, Rc, and Arc for different ownership patterns
use std::rc::Rc;
use std::sync::Arc;
use std::thread;
// Box: single owner, data on the heap
fn box_example() {
let boxed = Box::new(vec![1, 2, 3, 4, 5]);
println!("Boxed vec: {:?}", boxed);
// Useful for: recursive types, large objects, trait objects
}
// Rc: reference counting, multiple owners (single-thread)
fn rc_example() {
let data = Rc::new(String::from("shared data"));
let clone1 = Rc::clone(&data); // Increments the counter
let clone2 = Rc::clone(&data);
println!("Count: {}", Rc::strong_count(&data)); // 3
println!("All share: {}, {}, {}", data, clone1, clone2);
} // Freed when counter reaches 0
// Arc: thread-safe Rc (Atomic Reference Counting)
fn arc_example() {
let data = Arc::new(vec![1, 2, 3]);
let handles: Vec<_> = (0..3).map(|i| {
let data_clone = Arc::clone(&data);
thread::spawn(move || {
println!("Thread {}: {:?}", i, data_clone);
})
}).collect();
for handle in handles {
handle.join().unwrap();
}
}
fn main() {
box_example();
rc_example();
arc_example();
}ã¹ããŒããã€ã³ã¿ã®éžæã¯æææš©ãã¿ãŒã³ã«äŸåããŸãïŒåäžïŒBoxïŒãã·ã³ã°ã«ã¹ã¬ããã§ã®å ±æïŒRcïŒããã«ãã¹ã¬ããã§ã®å ±æïŒArcïŒã§ãã
å®çšçãªæææš©ãã¿ãŒã³
æææš©ã·ã¹ãã ãäžå¿ã«ã³ãŒããæ§é åããããã®äžè¬çãªãã¿ãŒã³ã瀺ããŸãã
// Practical patterns for ownership management
// Pattern 1: Builder pattern with chained ownership
struct RequestBuilder {
url: String,
headers: Vec<(String, String)>,
timeout: Option<u64>,
}
impl RequestBuilder {
fn new(url: &str) -> Self {
RequestBuilder {
url: url.to_string(),
headers: Vec::new(),
timeout: None,
}
}
// Consumes self and returns the new self
fn header(mut self, key: &str, value: &str) -> Self {
self.headers.push((key.to_string(), value.to_string()));
self // Returns ownership
}
fn timeout(mut self, seconds: u64) -> Self {
self.timeout = Some(seconds);
self
}
fn build(self) -> Request {
Request {
url: self.url,
headers: self.headers,
timeout: self.timeout.unwrap_or(30),
}
}
}
struct Request {
url: String,
headers: Vec<(String, String)>,
timeout: u64,
}
// Pattern 2: Cow (Copy-on-Write) to avoid allocations
use std::borrow::Cow;
fn process_text(input: &str) -> Cow<str> {
if input.contains("REPLACE") {
// Allocation only if modification needed
Cow::Owned(input.replace("REPLACE", "NEW"))
} else {
// No allocation, returns a reference
Cow::Borrowed(input)
}
}
// Pattern 3: Take to extract from an Option
fn extract_value(data: &mut Option<String>) -> String {
data.take().unwrap_or_else(|| String::from("default"))
// take() replaces with None and returns ownership of the value
}
fn main() {
// Builder pattern
let request = RequestBuilder::new("https://api.example.com")
.header("Authorization", "Bearer token")
.header("Content-Type", "application/json")
.timeout(60)
.build();
println!("URL: {}, Timeout: {}s", request.url, request.timeout);
// Cow pattern
let text1 = process_text("hello world"); // No allocation
let text2 = process_text("hello REPLACE"); // Allocation
println!("{} | {}", text1, text2);
// Take pattern
let mut optional = Some(String::from("extracted"));
let value = extract_value(&mut optional);
println!("Value: {}, Option: {:?}", value, optional); // None
}ãããã®ãã¿ãŒã³ã¯æææš©ã·ã¹ãã ãæŽ»çšããŠã人éå·¥åŠçã§é«æ§èœãªAPIãäœæããŸãã
ä»ããç·Žç¿ãå§ããŸãããïŒ
颿¥ã·ãã¥ã¬ãŒã¿ãŒãšæè¡ãã¹ãã§ç¥èããã¹ãããŸãããã
ãŸãšã
Rustã®æææš©ãšåçšã·ã¹ãã ã¯ãã¡ã¢ãªç®¡çã«ããããã©ãã€ã ã·ããã衚ããŠããŸããäžåºŠãã¹ã¿ãŒããã°ã髿§èœã§å®å šãªã³ãŒããæžãããã®åŒ·åãªå³æ¹ãšãªããŸãã
éèŠãªãã€ã³ãïŒ
â æææš©ã®3ã€ã®ã«ãŒã«ïŒåäžã®ææè ãæææš©ã®è»¢éãèªådrop
â åçšïŒè€æ°ã®äžå€åç §ããŸãã¯1ã€ã®æä»çå¯å€åç §
â ã©ã€ãã¿ã€ã ïŒåç §ã®ã©ã€ãã¿ã€ã éã®é¢ä¿ã泚éãã
â å éšå¯å€æ§ïŒå®è¡æã«æ€èšŒãããå¯å€æ§ã®ããã®RefCellãšCell
â ã¹ããŒããã€ã³ã¿ïŒBoxïŒåäžïŒãRcïŒå ±æïŒãArcïŒthread-safeïŒ
â å®çšçãªãã¿ãŒã³ïŒã€ãã£ãªããã£ãã¯ãªAPIã®ããã®BuilderãCowãTake
ãããŒãã§ãã«ãŒã¯æåã¯å³ããæãããããããŸããããå ±åãããåãšã©ãŒã¯åé¿ãããæœåšçãªãã°ã衚ããŸããå®è·µãéããŠãæææš©ã®èгç¹ã§èããããšãèªç¶ã«ãªãããã¹ãŠã®èšèªã«ãããã³ãŒãå質ãåäžããŸãã
ä»ããç·Žç¿ãå§ããŸãããïŒ
颿¥ã·ãã¥ã¬ãŒã¿ãŒãšæè¡ãã¹ãã§ç¥èããã¹ãããŸãããã
ã¿ã°
å ±æ
é¢é£èšäº

Rustæææš©ãšåçšã培åºè§£èª¬ -- ã¡ã¢ãªå®å šæ§ã®ä»çµã¿ãšå®è·µãã¿ãŒã³
Rustã®æææš©ãåçšãã©ã€ãã¿ã€ã ã®ä»çµã¿ãã³ãŒãäŸãšãšãã«è©³ãã解説ããŸãããããŒãã§ãã«ãŒã®ãšã©ãŒå¯ŸåŠæ³ãå®åã§äœ¿ãããã¿ãŒã³ã玹ä»ããŸãã

Rust颿¥è³ªåïŒ2026幎çå®å šã¬ã€ã
Rustã®æè¡é¢æ¥ã§é »åºã®25åãå®å šç¶²çŸ ãæææš©ãåçšãã©ã€ãã¿ã€ã ããã¬ã€ããasync/awaitã䞊è¡åŠçã«ã€ããŠè©³çްãªåçãšã³ãŒãäŸä»ãã§è§£èª¬ããŸãã

Rustå ¥éïŒçµéšè ã®ããã®åºç€ã¬ã€ã 2026幎ç
C++ãJavaãPythonã®çµéšã掻ãããŠRustãå¹ççã«åŠã¶ããã®ã¬ã€ãã§ããæææš©ãåçšãã©ã€ãã¿ã€ã ãªã©ãRustç¹æã®æŠå¿µãäœç³»çã«è§£èª¬ããŸãã