Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Управление пакетами: Cargo против NuGet

Что вы узнаете: Cargo.toml против .csproj, спецификаторы версий, Cargo.lock, флаги функций для условной компиляции, а также распространённые команды Cargo и их аналоги в NuGet/dotnet.

Сложность: 🟢 Начальный

Объявление зависимостей

Зависимости NuGet в C#

<!-- MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>
  
  <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
  <PackageReference Include="Serilog" Version="3.0.1" />
  <PackageReference Include="Microsoft.AspNetCore.App" />
  
  <ProjectReference Include="../MyLibrary/MyLibrary.csproj" />
</Project>

Зависимости Cargo в Rust

# Cargo.toml
[package]
name = "my_app"
version = "0.1.0"
edition = "2021"

[dependencies]
serde_json = "1.0"               # Из crates.io (как NuGet)
serde = { version = "1.0", features = ["derive"] }  # С функциями
log = "0.4"
tokio = { version = "1.0", features = ["full"] }

# Локальные зависимости (как ProjectReference)
my_library = { path = "../my_library" }

# Зависимости из git
my_git_crate = { git = "https://github.com/user/repo" }

# Зависимости для разработки (как тестовые пакеты)
[dev-dependencies]
criterion = "0.5"               # Бенчмарки
proptest = "1.0"               # Property-тестирование

Управление версиями

Версионирование пакетов в C#

<!-- Централизованное управление пакетами (Directory.Packages.props) -->
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  
  <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
  <PackageVersion Include="Serilog" Version="3.0.1" />
</Project>

<!-- packages.lock.json для воспроизводимых сборок -->

Управление версиями в Rust

# Cargo.toml — семантическое версионирование
[dependencies]
serde = "1.0"        # Совместимо с 1.x.x (>=1.0.0, <2.0.0)
log = "0.4.17"       # Совместимо с 0.4.x (>=0.4.17, <0.5.0)
regex = "=1.5.4"     # Точная версия
chrono = "^0.4"      # Требования с кареткой (по умолчанию)
uuid = "~1.3.0"      # Требования с тильдой (>=1.3.0, <1.4.0)

# Cargo.lock — точные версии для воспроизводимых сборок (генерируется автоматически)
[[package]]
name = "serde"
version = "1.0.163"
# ... точное дерево зависимостей

Источники пакетов

Источники пакетов в C#

<!-- nuget.config -->
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="MyCompanyFeed" value="https://pkgs.dev.azure.com/company/_packaging/feed/nuget/v3/index.json" />
  </packageSources>
</configuration>

Источники пакетов в Rust

# .cargo/config.toml
[source.crates-io]
replace-with = "my-awesome-registry"

[source.my-awesome-registry]
registry = "https://my-intranet:8080/index"

# Альтернативные реестры
[registries]
my-registry = { index = "https://my-intranet:8080/index" }

# В Cargo.toml
[dependencies]
my_crate = { version = "1.0", registry = "my-registry" }

Сравнение распространённых команд

ЗадачаКоманда C#Команда Rust
Восстановить пакетыdotnet restorecargo fetch
Добавить пакетdotnet add package Newtonsoft.Jsoncargo add serde_json
Удалить пакетdotnet remove package Newtonsoft.Jsoncargo remove serde_json
Обновить пакетыdotnet updatecargo update
Список пакетовdotnet list packagecargo tree
Аудит безопасностиdotnet list package --vulnerablecargo audit
Чистая сборкаdotnet cleancargo clean

Features: условная компиляция

Условная компиляция в C#

#if DEBUG
    Console.WriteLine("Debug mode");
#elif RELEASE
    Console.WriteLine("Release mode");
#endif

// Функции в файле проекта
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
    <DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>

Feature-флаги в Rust

# Cargo.toml
[features]
default = ["json"]              # Функции по умолчанию
json = ["serde_json"]          # Функция, включающая serde_json
xml = ["serde_xml"]            # Альтернативная сериализация
advanced = ["json", "xml"]     # Составная функция

[dependencies]
serde_json = { version = "1.0", optional = true }
serde_xml = { version = "0.4", optional = true }
#![allow(unused)]
fn main() {
// Условная компиляция на основе функций
#[cfg(feature = "json")]
use serde_json;

#[cfg(feature = "xml")]
use serde_xml;

pub fn serialize_data(data: &MyStruct) -> String {
    #[cfg(feature = "json")]
    return serde_json::to_string(data).unwrap();
    
    #[cfg(feature = "xml")]
    return serde_xml::to_string(data).unwrap();
    
    #[cfg(not(any(feature = "json", feature = "xml")))]
    return "No serialization feature enabled".to_string();
}
}

Использование внешних крейтов

Популярные крейты для разработчиков C#

Библиотека C#Крейт RustНазначение
System.Text.Json / Newtonsoft.Jsonserde_jsonСериализация JSON
HttpClientreqwestHTTP-клиент
Entity Frameworkdiesel / sqlxORM / инструментарий SQL
NLog/Seriloglog + env_loggerЛогирование
xUnit/NUnitВстроенный #[test]Модульное тестирование
MoqmockallМоки
FlurlurlРабота с URL
PollytowerПаттерны отказоустойчивости

Пример: миграция HTTP-клиента

// Использование HttpClient в C#
public class ApiClient
{
    private readonly HttpClient _httpClient;
    
    public async Task<User> GetUserAsync(int id)
    {
        var response = await _httpClient.GetAsync($"/users/{id}");
        var json = await response.Content.ReadAsStringAsync();
        return System.Text.Json.JsonSerializer.Deserialize<User>(json);
    }
}
#![allow(unused)]
fn main() {
// Использование reqwest в Rust
use reqwest;
use serde::Deserialize;

#[derive(Deserialize)]
struct User {
    id: u32,
    name: String,
}

struct ApiClient {
    client: reqwest::Client,
}

impl ApiClient {
    async fn get_user(&self, id: u32) -> Result<User, reqwest::Error> {
        let user = self.client
            .get(&format!("https://api.example.com/users/{}", id))
            .send()
            .await?
            .json::<User>()
            .await?;
        
        Ok(user)
    }
}
}