Vec
String
std::collection::Hashmap
プレゼン20分くらい+議論10分位で18:30前後終了を目指します。
配列がオブジェクト(トレイト?)になったと思えば良いです。
APIリファレンスには
A contiguous growable array type, written Vec<T> but pronounced 'vector'
と書いてあり"ベクター"と読むそうです
let v = vec![1,2,3]; // マクロで生成
let mut v = Vec::new(); // Vecのメンバ関数で生成
v.push(5); // push で値を追加
v.push(6);
// 添字記法かgetメソッドを使用してベクタの要素にアクセス
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50; // *は参照外し
}
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
forで回してmatchとかする使い方できそう
let v = vec![1, 2, 3, 4, 5];
let does_not_exist = &v[100]; // -> panic !!!
let does_not_exist = v.get(100); // -> None Optionが返る
{
let v = vec![1, 2, 3, 4];
// vで作業をする
} // <- vはここでスコープを抜け、解放される
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);// -> エラー!!上で一度不変借用してるので可変借用できない
println!("The first element is: {}", first);
pop , clear , as_slice , append, remove , len …etc
一般的なコレクションにあるメソッドはだいたいありそうです。
文字列でUTF-8でエンコードされたテキストを保持する
他にもCStringとかOsStringとか色々あるので詳しくはAPIで
let mut s = String::new();
let hello = "नमस्ते".to_string();// 文字列リテラルから生成;
let hello = String::from("Ciao")
let hello = String::from("こんにちは");
let mut s = String::from("foo");
s.push_str("bar");// 文字列スライスを足す
s.push('l'); //pushで足せるのは'文字'
let one = String::from("Hello, ");
let two = String::from("world!");
let s = one + &two; // oneはムーブされ、もう使用できないことに注意
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &s2 + "-" + &s3;
// 2個以上ならformat!が使いやすい
let s = format!("{}-{}-{}", s1, s2, s3);
let s1 = String::from("hello");
let h = s1[0]; // <- コンパイルエラー
let hello = "Здравствуйте"; // &strに範囲アクセスならOK
let s = &hello[0..4]; // Зд
let s = &hello[0..1]; // panic! 2バイト文字の頭1バイトのみにアクセス
この辺に色々書いてます。
2バイト文字の扱いが難しい等の理由があるようです。
for c in "नमस्ते".chars() {
println!("{}", c); // 文字を一つづつ出力
}
for b in "नमस्ते".bytes() {
println!("{}", b); //文字コード出力
}
Rustでは、Stringデータを正しく扱うことが、全てのRustプログラムにとっての既定動作になっているわけであり、 これは、プログラマがUTF-8データを素直に扱う際に、よりしっかり考えないといけないことを意味します。 このトレードオフにより、他のプログラミング言語で見えるよりも文字列の複雑性がより露出していますが、 ASCII以外の文字に関するエラーを開発の後半で扱わなければならない可能性が排除されているのです。
HashMap<K, V>は、 K型のキーとV型の値の対応関係を保持します。
他の言語で、辞書型とか連想配列とか言われたりするヤツです。
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// vectorから作ることもできます
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
let team_name = String::from("Blue");
let score = scores.get(&team_name); //getで値にアクセス
//for ループも回せます
for (key, value) in &scores {
println!("{}: {}", key, value);
}
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25); //上書き
// entryでキーの存在をチェック
// or_insertはキーが無かったときのみデータを挿入する
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores); // {"Blue": 25}
use std::collections::HashMap;
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
// or_insertはキーに対する値の可変参照を返す
let count = map.entry(word).or_insert(0);
//count にはmapのエントリに対する可変参照が入ってる
*count += 1;
}
println!("{:?}", map);
BuildHasherトレイトを実装した型を使えば独自のハッシュ関数を使えます。
(オレオレハッシュ関数はあまり感心しませんが。。。)
章末に練習問題が付いています
整数のリストが与えられ、ベクタを使って
を返してください。
use std::collections::HashMap;
/// 平均
pub fn mean(data: &Vec<i32>) -> f64 {
let mut sum = 0;
for datum in data.iter() {
sum += datum;
}
sum as f64 / data.len() as f64
}
/// 中央値
pub fn median(data: &Vec<i32>) -> i32 {
let mut clone_data = data.clone();
clone_data.sort();
let x :f64 = clone_data.len() as f64 /2.0_f64.floor();
clone_data[x as usize]
}
/// 最瀕値
pub fn mode(data: &Vec<i32>) -> i32 {
let mut counts: HashMap<i32,i32> = HashMap::new();
let mut max_count = 0;
let mut mode: &i32 = &0;
for datum in data.iter(){
let counter = counts.entry(*datum).or_insert(0);
*counter += 1;
if *counter > max_count{
max_count = *counter;
mode = datum;
}
}
println!("{:?}",counts);
println!("{:?}",data);
println!("mode {:?}", mode);
*mode
}
// 11章を参照するとユニットテストはここが良いみたい
#[cfg(test)]
mod tests {
use super::*;
use rand::prelude::*;
#[test]
fn test_mean() {
let array = vec![1,2,3,4,5,6,7,8,9,10];
assert_eq!(mean(&array), 5.5);
}
#[test]
fn test_median() {
let mut rng = rand::thread_rng();
let mut array = vec![0,1,2,3,4,5,6,7,8,9,10];
array.shuffle(&mut rng);
assert_eq!(median(&array),5);
}
#[test]
fn test_mode() {
let mut array = Vec::new();
for i in 0..=10 as i32 {
for _ in 0..=i as i32 {
array.push(i);
}
}
let mut rng = rand::thread_rng();
array.shuffle(&mut rng);
assert_eq!(mode(&array),10);
}
}
文字列をピッグ・ラテン(訳注: 英語の言葉遊びの一つ)に変換してください。各単語の最初の子音は、 単語の終端に移り、"ay"が足されます。従って、"first"は"irst-fay"になります。ただし、 母音で始まる単語には、お尻に"hay"が付け足されます("apple"は"apple-hay"になります)。 UTF-8エンコードに関する詳細を心に留めておいてください!
fn is_vowel(c : char) -> bool {
c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'
|| c == 'A' || c == 'E'|| c == 'I' || c == 'O' || c == 'U'
}
pub fn get_pig_latin_word(word: &str) -> String{
// 母音が頭文字の場合
if word.starts_with(is_vowel){
return word.to_string() + &String::from("hay");
}
let mut word_vec :Vec<char> = word.clone().chars().collect();
// 大文字が頭にあった場合
if word.starts_with(char::is_uppercase) {
// 1文字目を小文字 2文字目を大文字に
word_vec[0] = word_vec[0].to_ascii_lowercase();
word_vec[1] = word_vec[1].to_ascii_uppercase();
}
let s :String = word_vec.into_iter().collect();
let word = &s;
// 頭1文字子音切り出し + 末尾にay
[ &word[1..],&word[..1],"ay"].concat().to_string()
}
pub fn translate(text: &String) -> String {
let mut translated_string = String::new();
for mut word_option in text.split_ascii_whitespace(){
let mut terminal : Option<&str> = None;
//'.','?','!',':',','で終わっていた場合の処理
if word_option.ends_with(".") {
// word_optionから末尾を取り除く
println!("word_option :: {:?}",word_option);
let end = word_option.len()-1;
let t = &word_option[end..];
word_option = &word_option[..end];
println!("t :: {:?}",t);
terminal = Some(t);
}
let word = get_pig_latin_word(word_option);
translated_string += &word;
match terminal {
Some(e) => {
println!("e :: {:?}",e);
translated_string.push_str(e)
},
None => translated_string.push_str(" "),
}
}
translated_string
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ascii() {
let ascii = 'a';
let non_ascii = '❤';
let q = '?';
assert!(ascii.is_ascii());
assert!(q.is_ascii());
assert!(!q.is_ascii_alphabetic());
assert!(!q.is_alphabetic());
assert!(!non_ascii.is_ascii());
}
#[test]
fn test_string() {
assert_eq!(String::from("This is a pen."),String::from("This is a pen."));
}
#[test]
fn test_translate() {
assert_eq!(translate(&String::from("I don't understand.")),
String::from("Ihay on'tday understandhay."));
assert_eq!(translate(&String::from("This is a pen.")),
String::from("Histay ishay ahay enpay."));
assert_eq!(translate(&String::from("Good morning")),
String::from("Oodgay orningmay "));
}
#[test]
fn test_get_pig_latin_word(){
assert_eq!(get_pig_latin_word("I"),"Ihay");
assert_eq!(get_pig_latin_word("understand"),"understandhay");
assert_eq!(get_pig_latin_word("don't"),"on'tday");
assert_eq!(get_pig_latin_word("good"),"oodgay");
assert_eq!(get_pig_latin_word("morning"),"orningmay");
assert_eq!(get_pig_latin_word("Hello"),"Ellohay");
assert_eq!(get_pig_latin_word("first"),"irstfay");
assert_eq!(get_pig_latin_word("First"),"Irstfay");
assert_eq!(get_pig_latin_word("apple"),"applehay");
assert_eq!(get_pig_latin_word("Apple"),"Applehay");
}
}
ハッシュマップとベクタを使用して、ユーザに会社の部署に雇用者の名前を追加させられるテキストインターフェイスを作ってください。
例えば、"Add Sally to Engineering"(開発部門にサリーを追加)や"Add Amir to Sales"(販売部門にアミールを追加)などです。
それからユーザに、ある部署にいる人間の一覧や部署ごとにアルファベット順で並べ替えられた会社の全人間の一覧を扱わせてあげてください。
use std::collections::HashMap;
type Employees = HashMap<String,String>;
fn add(employees :&mut Employees,command:&str){
let obj :Vec<&str>= command.splitn(2," to ").collect();
println!("add {:?} as {:?}",obj[0].to_string(), obj[1].to_string());
employees.insert(obj[0].to_string(), obj[1].to_string());
}
fn list(employees :&Employees,command:&str){
if employees.is_empty() {
println!("No Data");
return ()
}
println!("list {:?}",command);
if command == "All" {
for name in employees.keys(){
println!("{:?}",name);
}
return ()
}
for (name , depart) in employees.iter(){
if command == depart {
println!("{:?}",name);
}
}
}
fn help(){
println!("**********This is help************")
}
pub fn command(employees :&mut Employees,command_string: String) -> bool{
let command: Vec<&str> = command_string.splitn(2,' ').collect();
println!("{:?}",command[0]);
match command[0].trim() {
"Exit" => false,
"Add" => {
if command.len() > 1 {
add(employees,command[1].trim());
}
true
},
"List" => {
if command.len() > 1 {
list(employees,command[1].trim());
}
true
},
_ => {
help();
true
},
}
}
use std::io;
pub fn run(){
let mut employees = Employees::new();
loop {
println!("command? >>");
let mut command_string = String::new();
io::stdin().read_line(&mut command_string)
.expect("Failed to read line");
if ! command(&mut employees, command_string) {
break;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_command() {
let mut employees = Employees::new();
assert_eq!(command(&mut employees,"Add a to B".to_string()),true);
assert_eq!(command(&mut employees,"List All".to_string()),true);
assert_eq!(command(&mut employees,"List B".to_string()),true);
assert_eq!(command(&mut employees,"Exit".to_string()),false);
assert_eq!(command(&mut employees,"".to_string()),true);
}
#[test]
fn test_add(){
let mut employees = Employees::new();
add(&mut employees,&"a to B".to_string());
println!("{:?}",employees);
assert_eq!(employees.get(&"a".to_string()), Some(&"B".to_string()));
}
}