RNA Transcription
1. Readme
RNA 转录
给定 DNA 链,返回其 RNA 补体(每个 RNA 转录).
DNA 和 RNA 链都是核苷酸序列.
DNA 中发现的四个核苷酸是腺嘌呤(A),胞嘧啶(C),鸟嘌呤(G)和胸腺嘧啶(T).
RNA 中发现的四个核苷酸是腺嘌呤(A),胞嘧啶(C),鸟嘌呤(G)和尿嘧啶(T).
给定 DNA 链,其转录的 RNA 链,通过用其互补物替换每个核苷酸而形成:
G
- >C
C
- >G
T
- >A
A
- >U
关于 Rust 实现的注释
通过在公共结构中使用私有字段,new
函数会返回Option
要么Result
(在这里DNA::new
&RNA::new
),我们可以保证DNA
内部的表达是正确的。因为每个有效的 DNA 字符串,都有一个有效的 RNA 字符串,所以我们不需要从to_rna
返回一个Result
/Option
.
这解释了您将在测试中看到的类型签名。
资源
Hyperphysicshttp://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html
2. 开始你的表演
#[derive(Debug, PartialEq)] pub struct DNA; #[derive(Debug, PartialEq)] pub struct RNA; impl DNA { pub fn new(dna: &str) -> Result<DNA, usize> { unimplemented!("Construct new DNA from '{}' string. If string contains invalid nucleotides return index of first invalid nucleotide", dna); } pub fn to_rna(self) -> RNA { unimplemented!("Transform DNA {:?} into corresponding RNA", self); } } impl RNA { pub fn new(rna: &str) -> Result<RNA, usize> { unimplemented!("Construct new RNA from '{}' string. If string contains invalid nucleotides return index of first invalid nucleotide", rna); } }
3. 测试代码查看
# #![allow(unused_variables)] #fn main() { #[test] fn test_valid_dna_input() { assert!(DNA::new("GCTA").is_ok()); } #[test] //#[ignore] fn test_valid_rna_input() { assert!(RNA::new("CGAU").is_ok()); } #[test] //#[ignore] fn test_invalid_dna_input() { // Invalid character assert_eq!(DNA::new("X").err(), Some(0)); // Valid nucleotide, but invalid in context assert_eq!(DNA::new("U").err(), Some(0)); // Longer string with contained errors assert_eq!(DNA::new("ACGTUXXCTTAA").err(), Some(4)); } #[test] //#[ignore] fn test_invalid_rna_input() { // Invalid character assert!(RNA::new("X").is_err()); // Valid nucleotide, but invalid in context assert!(RNA::new("T").is_err()); // Longer string with contained errors assert!(RNA::new("ACGUTTXCUUAA").is_err()); } #[test] //#[ignore] fn test_acid_equals_acid() { assert_eq!(DNA::new("CGA").unwrap(), DNA::new("CGA").unwrap()); assert_ne!(DNA::new("CGA").unwrap(), DNA::new("AGC").unwrap()); assert_eq!(RNA::new("CGA").unwrap(), RNA::new("CGA").unwrap()); assert_ne!(RNA::new("CGA").unwrap(), RNA::new("AGC").unwrap()); } #[test] //#[ignore] fn test_transcribes_cytosine_guanine() { assert_eq!(RNA::new("G").unwrap(), DNA::new("C").unwrap().to_rna()); } #[test] //#[ignore] fn test_transcribes_guanine_cytosine() { assert_eq!(RNA::new("C").unwrap(), DNA::new("G").unwrap().to_rna()); } #[test] //#[ignore] fn test_transcribes_adenine_uracil() { assert_eq!(RNA::new("U").unwrap(), DNA::new("A").unwrap().to_rna()); } #[test] //#[ignore] fn test_transcribes_thymine_to_adenine() { assert_eq!(RNA::new("A").unwrap(), DNA::new("T").unwrap().to_rna()); } #[test] //#[ignore] fn test_transcribes_all_dna_to_rna() { assert_eq!( RNA::new("UGCACCAGAAUU").unwrap(), DNA::new("ACGTGGTCTTAA").unwrap().to_rna() ) } #}
4. 答案
# #![allow(unused_variables)] #fn main() { /// The possible nucleotides in DNA and RNA #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Nucleotide { Adenine, Cytosine, Guanine, Thymine, Uracil, } impl Nucleotide { /// Parses a nucleotide from its character value, if valid. fn from_char(ch: char) -> Option<Nucleotide> { Some(match ch { 'A' => Nucleotide::Adenine, 'C' => Nucleotide::Cytosine, 'G' => Nucleotide::Guanine, 'T' => Nucleotide::Thymine, 'U' => Nucleotide::Uracil, _ => { return None; } }) } } /// A vector of nucleotides /// /// Guaranteed that Uracil is not present thanks to `new`. #[derive(Debug, Eq, PartialEq, Clone)] pub struct DNA(Vec<Nucleotide>); impl DNA { /// Parse a DNA string, checking it is valid. /// /// The error value is the first invalid character index (char index, not utf8). pub fn new(input: &str) -> Result<DNA, usize> { let mut out = Vec::new(); for (idx, ch) in input.chars().enumerate() { match Nucleotide::from_char(ch) { Some(Nucleotide::Uracil) | None => { return Err(idx); } Some(n) => { out.push(n); } } } Ok(DNA(out)) } pub fn to_rna(mut self) -> RNA { for nuc in self.0.iter_mut() { *nuc = match *nuc { Nucleotide::Adenine => Nucleotide::Uracil, Nucleotide::Cytosine => Nucleotide::Guanine, Nucleotide::Guanine => Nucleotide::Cytosine, Nucleotide::Thymine => Nucleotide::Adenine, Nucleotide::Uracil => unreachable!(), } } RNA(self.0) } } #[derive(Debug, Eq, PartialEq, Clone)] pub struct RNA(Vec<Nucleotide>); impl RNA { /// Parse a RNA string, checking it is valid. /// /// The error value is the first invalid character index (char index, not utf8). pub fn new(input: &str) -> Result<RNA, usize> { let mut out = Vec::new(); for (idx, ch) in input.chars().enumerate() { match Nucleotide::from_char(ch) { Some(Nucleotide::Thymine) | None => { return Err(idx); } Some(n) => { out.push(n); } } } Ok(RNA(out)) } } #}