How to group methods for working with a DNA sequence

Drashti Shah
Bioinformatics with Rust
2 min readDec 11, 2023
Generated with AI

A Rust struct for processing a DNA sequence: check for valid bases, transcribe, find the reverse complement, calculate length and GC content.

Code & Examples

use std::fmt;

fn main() {
let dna_seq: DNASeq = DNASeq::new("ACGTTT".to_string());
if dna_seq.is_valid() {
println! {"DNA Sequence: {}", dna_seq};
println! {"RNA Sequence: {}", dna_seq.to_rna()};
println! {"Reverse Complement: {}", dna_seq.reverse_complement()};
println! {"Length: {}", dna_seq.len()};
println! {"GC Content: {}%", dna_seq.gc_content() * 100.0};
} else {
println! {"Check the DNA sequence. It has invalid characters."};
}
}

struct DNASeq {
seq: String,
}

impl DNASeq {
// We can call DNASeq::new("ACGTTT".to_string()) because of this method
fn new(seq: String) -> Self {
Self { seq }
}

fn is_valid(&self) -> bool {
for base in self.seq.chars() {
match base {
'A' | 'C' | 'T' | 'G' => continue,
_ => return false,
}
}
true
}

fn len(&self) -> usize {
self.seq.len()
}

fn reverse_complement(&self) -> Self {
let rc = self
.seq
.chars()
// Reverse the string
.rev()
// Use map to replace characters
// For example, replace A with T
.map(|x| match x {
'A' => 'T',
'T' => 'A',
'G' => 'C',
'C' => 'G',
_ => x,
})
.collect();
Self::new(rc)
}

// Transcription
fn to_rna(&self) -> String {
let rna = self.seq.replace("T", "U");
rna
}

fn gc_content(&self) -> f32 {
let mut length = 0;
let mut count = 0;
for base in self.seq.chars() {
length += 1;
if base == 'G' || base == 'C' {
count += 1;
}
}
count as f32 / length as f32
}
}

// We can use dna_seq instead of dna_seq.seq in the print macro because of this trait
impl fmt::Display for DNASeq {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.seq)
}
}

Some notes on the code

  • The Display trait is a way to customise how a type is formatted for an empty format {}. This is useful in a print macro, writing to a file, or any other user-facing output. You can learn more about this here.
  • The write macro is a way to write formatted data into a buffer. A buffer is a temporary storage area that holds some data before it is transferred to another location like a file. The fmt::Formatter is a buffer.

Next Steps

--

--

Drashti Shah
Bioinformatics with Rust

ESG & climate data scientist by day. Aspiring computational biologist and game designer by night. A Rust fan who believes in an "open career".