Analyser, pas valider

En décembre, je suis tombé sur un article absolument merveilleux en anglais, consacré à l'utilisation du système de type de langue pour une classe de tâches plus large, pour augmenter la fiabilité des applications et la simplicité de la refactorisation. Malheureusement, à ce moment, j'étais trop occupé à écrire des articles sur la FA, qu'il était extrêmement important d'écrire pendant que les souvenirs étaient encore frais. Mais maintenant, quand j'ai fait face à cette tâche, j'ai finalement réussi à traduire cette merveilleuse note. La langue d'origine des exemples est Haskell, mais j'ai décidé de les copier dans un rast, pour une plus grande portée du public. Cependant, le langage ici est complètement sans importance, les conseils de cet article que j'utilise dans le développement quotidien sur C # et TypeScript complètement «banals», donc si vous essayez simplement d'écrire du code fiable et pris en charge, alors, quel que soit le langage, l'article sera dans le sujet.


Merci pour la relecture et l'aide à la traduction. Hirrolot, funkill et andreevlex



Sur une assez longue période de temps, j'ai eu du mal à trouver un moyen précis et simple d'expliquer ce qu'est la conception pilotée par type ( ci-après - TypeDD, environ Trans. ). Très souvent, ils m'ont demandé «Comment en êtes-vous arrivé à une telle décision?», Mais je n'ai pas eu de réponse satisfaisante. Je sais avec certitude que cela ne m'est pas venu comme une vision: j'avais un processus de conception itératif qui ne m'obligeait pas à sortir l'architecture «correcte» de rien pour le moment, mais jusqu'à présent, je n'ai pas été très capable d'interpréter ce processus pour les autres.


: JSON , , . , , , TypeDD, , , :


, .


TypeDD


, : TypeDD, , , . , . , , , .



, , , " ?". :


enum Void {}

fn foo(x: i32) -> Void

? , — , .. Void — , , Void. , , :


fn head<T>(xs: Vec<T>) -> T

. ? , - , , :


fn head<T>(xs: Vec<T>) -> T {
    match xs.as_slice() {
        [x, ..] => *x
    }
}

error[E0004]: non-exhaustive patterns: `&[]` not covered
 --> src/lib.rs:2:11
  |
2 |     match xs.as_slice() {
  |           ^^^^^^^^^^^^^ pattern `&[]` not covered
  |

, , , . , , [], . , .. , , , ! , , , ( , . .).



- . , . , " " - , . head, , .



, head , .. : , . , : . , , , , : , , . Rust Option:


fn head<T>(xs: Vec<T>) -> Option<T>

, headNone, , T:


fn head<T>(xs: Vec<T>) -> Option<T> {
    match xs.as_slice() {
        [x, ..] => Some(*x),
        [] => None,
    }
}

, ? , — … .


Option, , , head. . head None, , . , :


fn get_configuration_directories() -> Result<Vec<String>, &'static str> {
    let config_dirs_string = std::env::var("CONFIG_DIRS").map_err(|_| "cannot read env")?;
    let list: Vec<_> = config_dirs_string.split(',').map(|x| x.to_string()).collect();
    if list.is_empty() {
        return Err("CONFIG_DIRS cannot be empty");
    }
    Ok(list)
}

fn main() -> Result<(), &'static str> {
    let config_dirs = get_configuration_directories()?;
    match head(config_dirs) {
        Some(cacheDir) => initialize_cache(cacheDir),
        None => panic!("should never happen; already checked config_dirs is non-empty")
    }
    Ok(())
}

get_configuration_directories , . head main, , Option<&str> None, , , ! :


  1. -, . , , ?


  2. -, . , , , , , .


  3. , , . , get_configuration_directories , , , ? , main, "" , .



. None , get_configuration_directories .
, , .



, head , . , - : , , head , , , . ?


() head .


fn head<T>(xs: Vec<T>) -> T

, . , , : ( — Vec<T>). , head .


, , .
, NonEmptyVec . :


struct NonEmptyVec<T>(T, Vec<T>);

, NonEmptyVecT (, ) Vec<T>. , Vec<T> [], . , head :


fn head<T>(xs: NonEmptyVec<T>) -> T {
    xs.0
}

, , , , . :


fn get_configuration_directories() -> Result<NonEmptyVec<String>, &'static str> {
    let config_dirs_string = std::env::var("CONFIG_DIRS").map_err(|_| "cannot read env")?;
    let list: Vec<_> = config_dirs_string.split(',').map(|x| x.to_string()).collect();
    match non_empty(list) {
        Some(x) => Ok(x),
        None => Err("CONFIG_DIRS cannot be empty")
    }
}

fn main() -> Result<(), &'static str> {
    let config_dirs = get_configuration_directories()?;
    initialize_cache(head(config_dirs));
    Ok(())
}

, main ! , get_configuration_directories. NonEmptyVec Vec non_empty, :


fn non_empty<T>(list: Vec<T>) -> Option<NonEmptyVec<T>>

, Option , None : . , NonEmptyVec, ( !) , . , NonEmptyVec Vec<T> , .


head , :


  • , .


  • , get_configuration_directories , . , main , !



, head , non_empty:


fn old_head<T>(xs: Vec<T>) -> Option<T> {
    non_empty(xs).map(head)
}

, : head . , .



? , — , , . , : , , . :


fn validate_non_empty<T>(xs: Vec<T>) -> Result<(), UserError> {
    if !xs.is_empty() {
        Ok(())
    } else {
        Err(UserError::new("list cannot be empty"))
    }
}

fn parse_non_empty<T>(mut xs: Vec<T>) -> Result<NonEmptyVec<T>, UserError> {
    if !xs.is_empty() {
        let head = xs.remove(0);
        Ok(NonEmptyVec(head, xs))
    } else {
        Err(UserError::new("list cannot be empty"))
    }
}

: , , . : validate_non_empty (), , , parse_non_empty NonEmptyVec<T>, , . , parse_non_empty , validate_non_empty .


: validate_non_empty , parse_non_empty , . , parse_non_empty , , ", ". parse_non_empty. - , ? , , , , parse_non_empty , .


: ? , , , . , — — , - . , , , parse_non_empty : , .


: , , , ! Rust , :



: . - -, , . , , , , , .


, , : , . : - , . , NonEmpty : , .



, , , . , ? , , , ?


, . Ad-hoc , - . 2016 The Seven Turrets of Babel: A Taxonomy of LangSec Errors and How to Expunge Them :


— , , , ; , ( - ), "" .

, :


, . , - , .

, , , , , , , . — , , , — .


, — , , . , , , , "" . , , .


, : , , , . , .


, ,


, . ", , !", , , . "" "", "".


: .


, , , , , - . — , , :


fn check_no_duplicate_keys<K: Eq, V>(xs: &[(K,V)]) { ... }

"" — : . - , , , . , , , HashMap. , HashMap , , .


, , , , , . - , HashMap . , , , . check_no_duplicate_keys:


fn check_no_duplicate_keys<K: Eq, V>(xs: &[(K,V)]) -> HashMap<K,V> { ... }

, !


:


  1. , . , . , , .


  2. , . , . , , , .


    , . - , .



, , , , . , , - . , - !


, :


  • , . bool , ( , , . .). , — , , ,


  • Result<(), Error> . , - , , .


  • . , , , , , , . — -.


  • , , : .


    • . , , , .

  • , " " . , , , , , . (newtype) , - .



, . , error "impossible" - — , , . , , .



, -. , , — ! , .


. , — " " — . , , , . , — ! — . , — .


, , : Type Safety Back and Forth. , . Ghosts of Departed Proofs, , , .


, , , . , — , . , TypeDD, , , , . , , . , — .





, — , .


All Articles