Alıştırma: İfade Değerlendirmesi
Aritmetik ifadeler için basit bir özyinelemeli değerlendirici (recursive evaluator) yazalım.
Küçük bir aritmetik ifadenin bir örneği, 30
olarak değerlendirilen 10 + 20
olabilir. İfadeyi bir ağaç olarak temsil edebiliriz:
Daha büyük ve daha karmaşık bir ifade, 85
olarak değerlendirilen (10 * 9) + ((3 - 4) * 5)
olacaktır. Bunu çok daha büyük bir ağaç olarak temsil ediyoruz:
Kodda, ağacı iki türle temsil (represent) edeceğiz:
/// İki alt ifade (subexpression) üzerinde gerçekleştirilecek bir işlem. #[derive(Debug)] enum Operation { Add, Sub, Mul, Div, } /// Ağaç şeklinde bir ifade (expression). #[derive(Debug)] enum Expression { /// İki alt ifade üzerinde bir işlem. Op { op: Operation, left: Box<Expression>, right: Box<Expression> }, /// Bir değişmez (literal) değer Value(i64), }
Box
türü burada bir akıllı göstericidir (smart pointer) ve kursun ilerleyen bölümlerinde ayrıntılı olarak ele alınacaktır. Bir ifade, testlerde görüldüğü gibi Box::new
ile “kutulanabilir (boxed)”. Kutulanmış bir ifadeyi değerlendirmek için, onu “kutudan çıkarmak (unbox)” için referans kaldırma (deref) operatörünü (*
) kullanın: eval(*boxed_expr)
.
Kodu Rust deneme alanına (playground) kopyalayıp yapıştırın ve eval
’i uygulamaya başlayın. Son ürün testleri geçmelidir. todo!()
kullanmak ve testleri birer birer geçmek yardımcı olabilir. Bir testi geçici olarak #[ignore]
ile de atlayabilirsiniz:
#[test]
#[ignore]
fn test_value() { .. }
/// İki alt ifade (subexpression) üzerinde gerçekleştirilecek bir işlem. #[derive(Debug)] enum Operation { Add, Sub, Mul, Div, } /// Ağaç şeklinde bir ifade (expression). #[derive(Debug)] enum Expression { /// İki alt ifade üzerinde bir işlem. Op { op: Operation, left: Box<Expression>, right: Box<Expression> }, /// Bir değişmez (literal) değer Value(i64), } fn eval(e: Expression) -> i64 { todo!() } #[test] fn test_value() { assert_eq!(eval(Expression::Value(19)), 19); } #[test] fn test_sum() { assert_eq!( eval(Expression::Op { op: Operation::Add, left: Box::new(Expression::Value(10)), right: Box::new(Expression::Value(20)), }), 30 ); } #[test] fn test_recursion() { let term1 = Expression::Op { op: Operation::Mul, left: Box::new(Expression::Value(10)), right: Box::new(Expression::Value(9)), }; let term2 = Expression::Op { op: Operation::Mul, left: Box::new(Expression::Op { op: Operation::Sub, left: Box::new(Expression::Value(3)), right: Box::new(Expression::Value(4)), }), right: Box::new(Expression::Value(5)), }; assert_eq!( eval(Expression::Op { op: Operation::Add, left: Box::new(term1), right: Box::new(term2), }), 85 ); } #[test] fn test_zeros() { assert_eq!( eval(Expression::Op { op: Operation::Add, left: Box::new(Expression::Value(0)), right: Box::new(Expression::Value(0)) }), 0 ); assert_eq!( eval(Expression::Op { op: Operation::Mul, left: Box::new(Expression::Value(0)), right: Box::new(Expression::Value(0)) }), 0 ); assert_eq!( eval(Expression::Op { op: Operation::Sub, left: Box::new(Expression::Value(0)), right: Box::new(Expression::Value(0)) }), 0 ); } #[test] fn test_div() { assert_eq!( eval(Expression::Op { op: Operation::Div, left: Box::new(Expression::Value(10)), right: Box::new(Expression::Value(2)), }), 5 ) }