Структура AddrParseError
#![allow(unused)] fn main() { pub struct AddrParseError(_); }
Ошибка, которая может быть возвращена при анализе адреса IP или сокета.
Эта ошибка используется как ошибка типа для FromStr реализаций различных типов адресов в этом модуле, таких как IpAddr, SocketAddr, Ipv4Addr и других.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let invalid_str = "not-an-ip-address"; let err = IpAddr::from_str(invalid_str).unwrap_err(); println!("Ошибка анализа: {}", err); }
Методы
source
#![allow(unused)] fn main() { pub fn source(&self) -> Option<&(dyn Error + 'static)> }
Возвращает исходную ошибку, если таковая имеется.
Этот метод предоставляет доступ к исходной ошибке, которая привела к созданию этой ошибки анализа.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let invalid_str = "256.256.256.256"; // Неверный IP-адрес let err = IpAddr::from_str(invalid_str).unwrap_err(); if let Some(source) = err.source() { println!("Исходная ошибка: {}", source); } }
Трайт-реализации
Display
#![allow(unused)] fn main() { impl Display for AddrParseError }
Реализует отображение для AddrParseError.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let invalid_str = "not-an-ip"; let err = IpAddr::from_str(invalid_str).unwrap_err(); println!("Ошибка: {}", err); // Выводит читаемое сообщение об ошибке }
Debug
#![allow(unused)] fn main() { impl Debug for AddrParseError }
Реализует отладочное отображение для AddrParseError.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let invalid_str = "300.400.500.600"; let err = IpAddr::from_str(invalid_str).unwrap_err(); println!("Отладочная информация: {:?}", err); }
Error
#![allow(unused)] fn main() { impl Error for AddrParseError }
Реализует трейт Error для AddrParseError.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; use std::error::Error; let invalid_str = "invalid-ip-address"; let err = IpAddr::from_str(invalid_str).unwrap_err(); // Использование методов из трейта Error println!("Описание: {}", err); if let Some(source) = err.source() { println!("Источник: {}", source); } }
Clone, Copy
#![allow(unused)] fn main() { impl Clone for AddrParseError impl Copy for AddrParseError }
Реализует клонирование и копирование для AddrParseError.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let invalid_str = "999.999.999.999"; let err = IpAddr::from_str(invalid_str).unwrap_err(); let err_clone = err.clone(); // Клонирование ошибки println!("Оригинальная ошибка: {}", err); println!("Клонированная ошибка: {}", err_clone); }
Eq, PartialEq
#![allow(unused)] fn main() { impl Eq for AddrParseError impl PartialEq for AddrParseError }
Реализует сравнение для AddrParseError.
Примеры
#![allow(unused)] fn main() { use std::net::IpAddr; use std::str::FromStr; let err1 = IpAddr::from_str("invalid1").unwrap_err(); let err2 = IpAddr::from_str("invalid2").unwrap_err(); // Ошибки анализа считаются равными, независимо от входной строки assert_eq!(err1, err2); }
Примеры использования
Базовое использование с обработкой ошибок
use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; fn parse_ip_address(ip_str: &str) -> Result<IpAddr, String> { IpAddr::from_str(ip_str) .map_err(|e| format!("Неверный IP-адрес '{}': {}", ip_str, e)) } fn parse_socket_address(addr_str: &str) -> Result<SocketAddr, String> { SocketAddr::from_str(addr_str) .map_err(|e| format!("Неверный адрес сокета '{}': {}", addr_str, e)) } fn main() { // Тестирование валидных адресов let valid_ips = ["127.0.0.1", "::1", "192.168.1.1"]; for ip_str in &valid_ips { match parse_ip_address(ip_str) { Ok(ip) => println!("Успешно разобран IP: {}", ip), Err(e) => println!("Ошибка: {}", e), } } // Тестирование невалидных адресов let invalid_ips = ["256.256.256.256", "not_an_ip", "123.456.789.000"]; for ip_str in &invalid_ips { match parse_ip_address(ip_str) { Ok(ip) => println!("Успешно разобран IP: {}", ip), Err(e) => println!("Ошибка: {}", e), } } // Тестирование адресов сокетов let socket_str = "127.0.0.1:8080"; match parse_socket_address(socket_str) { Ok(addr) => println!("Успешно разобран адрес сокета: {}", addr), Err(e) => println!("Ошибка: {}", e), } }
Создание пользовательских парсеров с детальной обработкой ошибок
use std::net::{IpAddr, AddrParseError}; use std::str::FromStr; use std::error::Error; #[derive(Debug)] struct NetworkConfig { ip: IpAddr, port: u16, } impl NetworkConfig { fn from_str(s: &str) -> Result<Self, Box<dyn Error>> { let parts: Vec<&str> = s.split(':').collect(); if parts.len() != 2 { return Err("Ожидается формат 'IP:PORT'".into()); } let ip = IpAddr::from_str(parts[0]) .map_err(|e: AddrParseError| { format!("Неверный IP-адрес '{}': {}", parts[0], e) })?; let port = parts[1].parse::<u16>() .map_err(|e| { format!("Неверный порт '{}': {}", parts[1], e) })?; Ok(NetworkConfig { ip, port }) } } fn main() { let test_cases = [ "127.0.0.1:8080", "::1:9000", "invalid_ip:8080", "192.168.1.1:99999", // Неверный порт "no_colon", // Отсутствует разделитель ]; for test_case in &test_cases { println!("Разбор '{}':", test_case); match NetworkConfig::from_str(test_case) { Ok(config) => println!(" Успех: IP={}, PORT={}", config.ip, config.port), Err(e) => println!(" Ошибка: {}", e), } println!(); } }
Валидация пользовательского ввода
use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; fn validate_user_input(input: &str) -> Result<(), String> { // Попробуем разобрать как IP-адрес if let Ok(ip) = IpAddr::from_str(input) { if ip.is_loopback() { return Err("IP-адрес обратной петли не разрешен".to_string()); } if ip.is_unspecified() { return Err("Неспецифицированный IP-адрес не разрешен".to_string()); } println!("Валидный IP-адрес: {}", ip); return Ok(()); } // Попробуем разобрать как адрес сокета if let Ok(socket) = SocketAddr::from_str(input) { if socket.port() == 0 { return Err("Порт 0 не разрешен".to_string()); } println!("Валидный адрес сокета: {}", socket); return Ok(()); } Err(format!("'{}' не является валидным IP-адресом или адресом сокета", input)) } fn main() { let inputs = [ "127.0.0.1", "192.168.1.1", "0.0.0.0", "google.com:80", "256.256.256.256", "localhost:8080", "123.45.67.89:0", ]; for input in &inputs { println!("Валидация '{}':", input); match validate_user_input(input) { Ok(()) => println!(" ✓ Валидный ввод"), Err(e) => println!(" ✗ Ошибка: {}", e), } } }
Интеграция с другими типами ошибок
use std::net::{IpAddr, AddrParseError}; use std::str::FromStr; use thiserror::Error; #[derive(Error, Debug)] pub enum ConfigError { #[error("Ошибка анализа IP-адреса '{input}': {source}")] AddrParse { input: String, source: AddrParseError, }, #[error("Ошибка ввода-вывода: {0}")] Io(#[from] std::io::Error), #[error("Неверный формат конфигурации: {0}")] InvalidFormat(String), } pub fn parse_ip_with_detailed_error(ip_str: &str) -> Result<IpAddr, ConfigError> { IpAddr::from_str(ip_str) .map_err(|source| ConfigError::AddrParse { input: ip_str.to_string(), source, }) } pub fn load_config_from_file(filename: &str, ip_str: &str) -> Result<(), ConfigError> { // Имитация чтения файла println!("Чтение конфигурации из {}", filename); // Разбор IP-адреса с детализированной ошибкой let ip = parse_ip_with_detailed_error(ip_str)?; println!("Загружена конфигурация с IP: {}", ip); Ok(()) } fn main() { let test_cases = [ ("config1.txt", "192.168.1.1"), ("config2.txt", "invalid_ip"), ("config3.txt", "999.999.999.999"), ]; for (filename, ip_str) in &test_cases { println!("Обработка {} с IP {}", filename, ip_str); match load_config_from_file(filename, ip_str) { Ok(()) => println!(" ✓ Успех"), Err(e) => println!(" ✗ Ошибка: {}", e), } println!(); } }
Утилитарные функции для работы с ошибками анализа
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, AddrParseError}; use std::str::FromStr; fn analyze_parse_error(input: &str) { println!("Анализ ошибки для '{}':", input); // Проверяем различные типы адресов match IpAddr::from_str(input) { Ok(ip) => println!(" ✓ Валидный IP-адрес: {}", ip), Err(e) => { println!(" ✗ Ошибка анализа IP: {}", e); // Детальный анализ if let Ok(ipv4) = Ipv4Addr::from_str(input) { println!(" - Но это валидный IPv4: {}", ipv4); } else if let Ok(ipv6) = Ipv6Addr::from_str(input) { println!(" - Но это валидный IPv6: {}", ipv6); } else { println!(" - Не является валидным ни IPv4, ни IPv6"); } } } } fn suggest_correction(input: &str) -> Option<String> { // Простые эвристики для предложения исправлений let trimmed = input.trim(); // Убираем лишние пробелы if trimmed != input { return Some(trimmed.to_string()); } // Проверяем IPv6 без скобок if trimmed.contains(':') && !trimmed.starts_with('[') { let suggestion = format!("[{}]", trimmed); if IpAddr::from_str(&suggestion).is_ok() { return Some(suggestion); } } None } fn main() { let problematic_inputs = [ " 127.0.0.1 ", // Лишние пробелы "::1", // IPv6 без скобок для адреса сокета "192.168.001.001", // Ведущие нули "fe80::1%eth0", // IPv6 с зоной ]; for input in &problematic_inputs { analyze_parse_error(input); if let Some(suggestion) = suggest_correction(input) { println!(" 💡 Предложение: попробуйте '{}'", suggestion); if IpAddr::from_str(&suggestion).is_ok() { println!(" ✅ Предложение работает!"); } } println!(); } }
Распространенные сценарии ошибок
Неверные IPv4 адреса
"256.256.256.256"- октеты больше 255"192.168.1"- недостаточно октетов"192.168.1.1.1"- слишком много октетов"192.168.1."- незавершенный адрес
Неверные IPv6 адреса
"::fffff"- неверный формат"2001:db8::1::1"- множественные::"2001:db8:xyz::1"- неверные шестнадцатеричные цифры
Неверные адреса сокетов
"127.0.0.1:"- отсутствует порт"127.0.0.1:99999"- порт вне диапазона"[::1]"- IPv6 без порта