Swift實現股票圖:從基礎到高級

目錄

    • 一、核心實現方案
      • 1. 原生方案:使用 Core Graphics 繪制
      • 2. 使用第三方庫:Charts
      • 3. 跨平臺方案:使用 SwiftUI + Canvas
    • 二、技術指標實現
      • 1. 移動平均線 (MA)
      • 2. 布林帶 (Bollinger Bands)
      • 3. MACD (Moving Average Convergence Divergence)
    • 三、性能優化策略
      • 1. 數據分頁與懶加載
      • 2. 離屏渲染優化
      • 3. 手勢交互優化
    • 四、高級功能實現
      • 1. 十字線光標
      • 2. 多時間周期切換
    • 五、架構設計建議
      • 1、分層架構設計:
      • 2、性能優化總結表:
      • 3、跨平臺適配方案:
    • 六、推薦方案選擇
      • 1、根據需求選擇方案
      • 2、性能對比表

股票圖(尤其是K線圖)是金融應用的核心功能。下面我將詳細介紹多種實現方案,并提供完整的代碼示例和優化建議。

一、核心實現方案

1. 原生方案:使用 Core Graphics 繪制

優勢:

  • 完全可控,無依賴
  • 高性能,適合大數據量
  • 定制化程度高

實現代碼:

import UIKitstruct Candle {let date: Datelet open: Doublelet high: Doublelet low: Doublelet close: Doublelet volume: Double
}class StockChartView: UIView {var candles: [Candle] = [] {didSet {calculateMetrics()setNeedsDisplay()}}// 計算指標private var minPrice: Double = 0private var maxPrice: Double = 0private var maxVolume: Double = 0private var candleWidth: CGFloat = 0private var candleSpacing: CGFloat = 2override func draw(_ rect: CGRect) {super.draw(rect)guard let context = UIGraphicsGetCurrentContext() else { return }guard !candles.isEmpty else { return }drawGrid(context: context)drawCandles(context: context)drawVolume(context: context)drawIndicators(context: context)}private func calculateMetrics() {minPrice = candles.map { $0.low }.min() ?? 0maxPrice = candles.map { $0.high }.max() ?? 0// 添加10%的上下空間let priceRange = maxPrice - minPriceminPrice = minPrice - priceRange * 0.1maxPrice = maxPrice + priceRange * 0.1maxVolume = candles.map { $0.volume }.max() ?? 0// 計算蠟燭寬度let availableWidth = bounds.width - 40 // 左右邊距candleWidth = (availableWidth / CGFloat(candles.count)) - candleSpacing}private func drawGrid(context: CGContext) {context.setStrokeColor(UIColor.systemGray4.cgColor)context.setLineWidth(0.5)// 水平網格線let horizontalLines = 5for i in 0...horizontalLines {let y = bounds.height * CGFloat(i) / CGFloat(horizontalLines)context.move(to: CGPoint(x: 0, y: y))context.addLine(to: CGPoint(x: bounds.width, y: y))}// 垂直網格線let verticalLines = 6for i in 0...verticalLines {let x = bounds.width * CGFloat(i) / CGFloat(verticalLines)context.move(to: CGPoint(x: x, y: 0))context.addLine(to: CGPoint(x: x, y: bounds.height))}context.strokePath()}private func drawCandles(context: CGContext) {let chartHeight = bounds.height * 0.7 // 70%高度用于K線let topMargin: CGFloat = 20for (index, candle) in candles.enumerated() {let x = 20 + CGFloat(index) * (candleWidth + candleSpacing)// 計算價格對應的Y坐標func priceToY(_ price: Double) -> CGFloat {let priceRatio = (price - minPrice) / (maxPrice - minPrice)return topMargin + chartHeight * (1 - CGFloat(priceRatio))}let highY = priceToY(candle.high)let lowY = priceToY(candle.low)let openY = priceToY(candle.open)let closeY = priceToY(candle.close)// 繪制影線context.setStrokeColor(UIColor.gray.cgColor)context.setLineWidth(1)context.move(to: CGPoint(x: x + candleWidth/2, y: highY))context.addLine(to: CGPoint(x: x + candleWidth/2, y: lowY))context.strokePath()// 繪制實體let bodyHeight = max(1, abs(openY - closeY))let bodyY = min(openY, closeY)if candle.close > candle.open {context.setFillColor(UIColor.systemRed.cgColor) // 陽線} else {context.setFillColor(UIColor.systemGreen.cgColor) // 陰線}context.fill(CGRect(x: x, y: bodyY, width: candleWidth, height: bodyHeight))}}private func drawVolume(context: CGContext) {let volumeHeight = bounds.height * 0.3 // 30%高度用于成交量let volumeTop = bounds.height * 0.7 + 10for (index, candle) in candles.enumerated() {let x = 20 + CGFloat(index) * (candleWidth + candleSpacing)// 計算成交量高度let volumeRatio = CGFloat(candle.volume / maxVolume)let barHeight = volumeHeight * volumeRatio// 設置顏色(與K線一致)if candle.close > candle.open {context.setFillColor(UIColor.systemRed.cgColor)} else {context.setFillColor(UIColor.systemGreen.cgColor)}context.fill(CGRect(x: x, y: volumeTop + volumeHeight - barHeight, width: candleWidth, height: barHeight))}}private func drawIndicators(context: CGContext) {// 繪制移動平均線示例let movingAverage = calculateMovingAverage(period: 5)context.setStrokeColor(UIColor.blue.cgColor)context.setLineWidth(1.5)for (index, value) in movingAverage.enumerated() {let x = 20 + CGFloat(index) * (candleWidth + candleSpacing) + candleWidth/2let y = bounds.height * 0.7 * (1 - CGFloat((value - minPrice) / (maxPrice - minPrice))) + 20if index == 0 {context.move(to: CGPoint(x: x, y: y))} else {context.addLine(to: CGPoint(x: x, y: y))}}context.strokePath()}private func calculateMovingAverage(period: Int) -> [Double] {guard period > 0, candles.count >= period else { return [] }var averages: [Double] = []for i in 0..<candles.count {let start = max(0, i - period + 1)let end = ilet range = candles[start...end]let sum = range.reduce(0) { $0 + $1.close }averages.append(sum / Double(range.count))}return averages}
}

2. 使用第三方庫:Charts

優勢

  • 快速實現復雜圖表
  • 內置多種技術指標
  • 支持交互功能

實現步驟:

  1. 安裝 Charts 庫(通過 CocoaPods 或 SPM)
  2. 創建 K 線圖視圖
import UIKit
import Chartsclass StockChartViewController: UIViewController {@IBOutlet weak var candleStickChartView: CandleStickChartView!@IBOutlet weak var volumeChartView: BarChartView!override func viewDidLoad() {super.viewDidLoad()setupCharts()loadData()}private func setupCharts() {// 配置K線圖candleStickChartView.dragEnabled = truecandleStickChartView.setScaleEnabled(true)candleStickChartView.pinchZoomEnabled = truecandleStickChartView.xAxis.labelPosition = .bottomcandleStickChartView.legend.enabled = false// 配置成交量圖volumeChartView.dragEnabled = falsevolumeChartView.setScaleEnabled(false)volumeChartView.pinchZoomEnabled = falsevolumeChartView.xAxis.labelPosition = .bottomvolumeChartView.legend.enabled = falsevolumeChartView.leftAxis.enabled = false}private func loadData() {let candles = generateSampleData()// K線數據var candleEntries = [CandleChartDataEntry]()for (i, candle) in candles.enumerated() {let entry = CandleChartDataEntry(x: Double(i),shadowH: candle.high,shadowL: candle.low,open: candle.open,close: candle.close)candleEntries.append(entry)}let candleDataSet = CandleChartDataSet(entries: candleEntries, label: "K線")candleDataSet.increasingColor = .systemRedcandleDataSet.increasingFilled = truecandleDataSet.decreasingColor = .systemGreencandleDataSet.decreasingFilled = truecandleDataSet.shadowColor = .darkGraycandleDataSet.shadowWidth = 1candleStickChartView.data = CandleChartData(dataSet: candleDataSet)// 成交量數據var volumeEntries = [BarChartDataEntry]()for (i, candle) in candles.enumerated() {volumeEntries.append(BarChartDataEntry(x: Double(i), y: candle.volume))}let volumeDataSet = BarChartDataSet(entries: volumeEntries, label: "成交量")volumeDataSet.colors = candles.map { $0.close > $0.open ? .systemRed : .systemGreen }volumeChartView.data = BarChartData(dataSet: volumeDataSet)// 添加移動平均線let movingAverage = calculateMovingAverage(data: candles.map { $0.close }, period: 5)var lineEntries = [ChartDataEntry]()for (i, value) in movingAverage.enumerated() {lineEntries.append(ChartDataEntry(x: Double(i), y: value))}let lineDataSet = LineChartDataSet(entries: lineEntries, label: "5日均線")lineDataSet.colors = [.blue]lineDataSet.drawCirclesEnabled = falselineDataSet.lineWidth = 2candleStickChartView.data?.addDataSet(lineDataSet)}private func generateSampleData() -> [Candle] {// 生成示例數據...}private func calculateMovingAverage(data: [Double], period: Int) -> [Double] {// 計算移動平均...}
}

3. 跨平臺方案:使用 SwiftUI + Canvas

import SwiftUIstruct CandleChart: View {let candles: [Candle]@State private var visibleRange: ClosedRange<Int> = 0...50var body: some View {GeometryReader { geometry inZStack(alignment: .topLeading) {// 網格背景GridBackground()// K線圖CandlesView(candles: Array(candles[visibleRange]),width: geometry.size.width,height: geometry.size.height * 0.7).offset(y: 20)// 成交量圖VolumeView(candles: Array(candles[visibleRange]),width: geometry.size.width,height: geometry.size.height * 0.3).offset(y: geometry.size.height * 0.7 + 10)// 技術指標MovingAverageView(candles: Array(candles[visibleRange]),width: geometry.size.width,height: geometry.size.height * 0.7).offset(y: 20)}.gesture(DragGesture().onChanged { value in// 處理拖動邏輯})}}
}struct CandlesView: View {let candles: [Candle]let width: CGFloatlet height: CGFloatprivate var minPrice: Double { candles.map { $0.low }.min() ?? 0 }private var maxPrice: Double { candles.map { $0.high }.max() ?? 0 }private var candleWidth: CGFloat { (width - 40) / CGFloat(candles.count) - 2 }var body: some View {Canvas { context, size infor (index, candle) in candles.enumerated() {let x = 20 + CGFloat(index) * (candleWidth + 2) + candleWidth/2// 影線context.stroke(Path { path inpath.move(to: CGPoint(x: x, y: priceToY(candle.high)))path.addLine(to: CGPoint(x: x, y: priceToY(candle.low)))},with: .color(.gray),lineWidth: 1)// 實體let bodyRect = CGRect(x: 20 + CGFloat(index) * (candleWidth + 2),y: priceToY(max(candle.open, candle.close)),width: candleWidth,height: abs(priceToY(candle.open) - priceToY(candle.close)))context.fill(Path(bodyRect),with: .color(candle.close > candle.open ? .red : .green))}}.frame(height: height)}private func priceToY(_ price: Double) -> CGFloat {let priceRatio = (price - minPrice) / (maxPrice - minPrice)return height * (1 - CGFloat(priceRatio))}
}

二、技術指標實現

1. 移動平均線 (MA)

extension Array where Element == Candle {func movingAverage(period: Int) -> [Double] {guard period > 0, count >= period else { return [] }return self.indices.map { index inlet start = max(0, index - period + 1)let end = indexlet range = self[start...end]return range.reduce(0) { $0 + $1.close } / Double(range.count)}}
}

2. 布林帶 (Bollinger Bands)

struct BollingerBands {let upper: [Double]let middle: [Double] // 即MAlet lower: [Double]
}extension Array where Element == Candle {func bollingerBands(period: Int, multiplier: Double = 2) -> BollingerBands {let ma = movingAverage(period: period)guard ma.count == count else { return BollingerBands(upper: [], middle: [], lower: []) }let stdDev: [Double] = indices.map { index inlet start = max(0, index - period + 1)let end = indexlet range = self[start...end].map { $0.close }let average = ma[index]let variance = range.reduce(0) { $0 + pow($1 - average, 2) } / Double(range.count)return sqrt(variance)}let upper = zip(ma, stdDev).map { $0 + $1 * multiplier }let lower = zip(ma, stdDev).map { $0 - $1 * multiplier }return BollingerBands(upper: upper, middle: ma, lower: lower)}
}

3. MACD (Moving Average Convergence Divergence)

struct MACD {let macdLine: [Double]let signalLine: [Double]let histogram: [Double]
}extension Array where Element == Candle {func macd(fastPeriod: Int = 12, slowPeriod: Int = 26, signalPeriod: Int = 9) -> MACD {let fastEMA = exponentialMovingAverage(period: fastPeriod)let slowEMA = exponentialMovingAverage(period: slowPeriod)let macdLine = zip(fastEMA, slowEMA).map { $0 - $1 }let signalLine = macdLine.exponentialMovingAverage(period: signalPeriod)let histogram = zip(macdLine, signalLine).map { $0 - $1 }return MACD(macdLine: macdLine, signalLine: signalLine, histogram: histogram)}private func exponentialMovingAverage(period: Int) -> [Double] {guard count >= period else { return [] }var ema: [Double] = []let multiplier = 2.0 / Double(period + 1)// 第一個EMA是簡單移動平均let firstSMA = prefix(period).reduce(0) { $0 + $1.close } / Double(period)ema.append(firstSMA)// 計算后續EMAfor i in period..<count {let value = self[i].closelet prevEMA = ema[i - period]let currentEMA = (value - prevEMA) * multiplier + prevEMAema.append(currentEMA)}// 補齊前面的空值return Array(repeating: Double.nan, count: period - 1) + ema}
}

三、性能優化策略

1. 數據分頁與懶加載

class StockDataLoader {private let allCandles: [Candle]private var loadedCandles: [Candle] = []private let pageSize = 100init(candles: [Candle]) {self.allCandles = candles}func loadMore(completion: @escaping ([Candle]) -> Void) {let startIndex = loadedCandles.countguard startIndex < allCandles.count else { return }let endIndex = min(startIndex + pageSize, allCandles.count)let newCandles = Array(allCandles[startIndex..<endIndex])// 模擬網絡請求延遲DispatchQueue.global().asyncAfter(deadline: .now() + 0.3) {DispatchQueue.main.async {self.loadedCandles.append(contentsOf: newCandles)completion(self.loadedCandles)}}}func visibleCandles(for range: ClosedRange<Int>) -> [Candle] {guard !loadedCandles.isEmpty else { return [] }let start = max(range.lowerBound, 0)let end = min(range.upperBound, loadedCandles.count - 1)return Array(loadedCandles[start...end])}
}

2. 離屏渲染優化

class StockChartView: UIView {private var renderLayer: CALayer?override func draw(_ rect: CGRect) {if renderLayer == nil {renderOffscreen()}}private func renderOffscreen() {DispatchQueue.global(qos: .userInitiated).async {let format = UIGraphicsImageRendererFormat()format.scale = UIScreen.main.scalelet renderer = UIGraphicsImageRenderer(size: self.bounds.size, format: format)let image = renderer.image { context inself.drawContent(context: context.cgContext)}DispatchQueue.main.async {let layer = CALayer()layer.contents = image.cgImagelayer.frame = self.boundsself.layer.addSublayer(layer)self.renderLayer = layer}}}private func drawContent(context: CGContext) {// 繪制邏輯...}
}

3. 手勢交互優化

class InteractiveStockChartView: StockChartView {private var panStart: CGPoint = .zeroprivate var visibleCandleCount: Int = 50override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {super.touchesBegan(touches, with: event)panStart = touches.first?.location(in: self) ?? .zero}override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {guard let touchPoint = touches.first?.location(in: self) else { return }let deltaX = panStart.x - touchPoint.xlet candleDelta = Int(deltaX / (candleWidth + candleSpacing))if abs(candleDelta) > 0 {// 更新可見范圍visibleCandleCount = max(10, min(200, visibleCandleCount + candleDelta))setNeedsDisplay()panStart = touchPoint}}@objc func handlePinch(_ gesture: UIPinchGestureRecognizer) {let scale = gesture.scalelet newCount = Int(Double(visibleCandleCount) / scaleif gesture.state == .changed {visibleCandleCount = max(10, min(500, newCount))setNeedsDisplay()}}
}

四、高級功能實現

1. 十字線光標

class CrosshairView: UIView {var currentPosition: CGPoint? {didSet { setNeedsDisplay() }}override func draw(_ rect: CGRect) {guard let position = currentPosition else { return }guard let context = UIGraphicsGetCurrentContext() else { return }// 水平線context.setStrokeColor(UIColor.white.withAlphaComponent(0.7).cgColor)context.setLineWidth(0.5)context.setLineDash(phase: 0, lengths: [5, 5])context.move(to: CGPoint(x: 0, y: position.y))context.addLine(to: CGPoint(x: bounds.width, y: position.y))// 垂直線context.move(to: CGPoint(x: position.x, y: 0))context.addLine(to: CGPoint(x: position.x, y: bounds.height))context.strokePath()// 信息框drawInfoBox(at: position, in: context)}private func drawInfoBox(at position: CGPoint, in context: CGContext) {let boxWidth: CGFloat = 120let boxHeight: CGFloat = 80let boxX = position.x > bounds.width / 2 ? position.x - boxWidth - 10 : position.x + 10let boxY = position.y > bounds.height / 2 ? position.y - boxHeight : position.ylet boxRect = CGRect(x: boxX, y: boxY, width: boxWidth, height: boxHeight)// 背景context.setFillColor(UIColor.systemBackground.withAlphaComponent(0.9).cgColor)context.fill(boxRect)// 邊框context.setStrokeColor(UIColor.systemGray.cgColor)context.setLineWidth(1)context.stroke(boxRect)// 繪制文本信息let paragraphStyle = NSMutableParagraphStyle()paragraphStyle.alignment = .leftlet attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 12),.paragraphStyle: paragraphStyle,.foregroundColor: UIColor.label]let dateText = "日期: 2023-06-15"let priceText = "價格: 150.25"let volumeText = "成交量: 1.2M"dateText.draw(at: CGPoint(x: boxX + 8, y: boxY + 8), withAttributes: attributes)priceText.draw(at: CGPoint(x: boxX + 8, y: boxY + 28), withAttributes: attributes)volumeText.draw(at: CGPoint(x: boxX + 8, y: boxY + 48), withAttributes: attributes)}
}

2. 多時間周期切換

enum ChartTimeframe: String, CaseIterable {case oneMinute = "1分"case fiveMinutes = "5分"case fifteenMinutes = "15分"case thirtyMinutes = "30分"case oneHour = "1小時"case fourHours = "4小時"case oneDay = "日線"case oneWeek = "周線"case oneMonth = "月線"var interval: TimeInterval {switch self {case .oneMinute: return 60case .fiveMinutes: return 300case .fifteenMinutes: return 900case .thirtyMinutes: return 1800case .oneHour: return 3600case .fourHours: return 14400case .oneDay: return 86400case .oneWeek: return 604800case .oneMonth: return 2592000 // 近似值}}
}class TimeframeSelector: UIView {var selectedTimeframe: ChartTimeframe = .oneDay {didSet { updateSelection() }}private var buttons: [UIButton] = []override init(frame: CGRect) {super.init(frame: frame)setupView()}private func setupView() {let stackView = UIStackView()stackView.axis = .horizontalstackView.distribution = .fillEquallystackView.spacing = 8for timeframe in ChartTimeframe.allCases {let button = UIButton(type: .system)button.setTitle(timeframe.rawValue, for: .normal)button.titleLabel?.font = UIFont.systemFont(ofSize: 14)button.addTarget(self, action: #selector(timeframeTapped(_:)), for: .touchUpInside)button.tag = ChartTimeframe.allCases.firstIndex(of: timeframe) ?? 0buttons.append(button)stackView.addArrangedSubview(button)}addSubview(stackView)stackView.translatesAutoresizingMaskIntoConstraints = falseNSLayoutConstraint.activate([stackView.topAnchor.constraint(equalTo: topAnchor),stackView.bottomAnchor.constraint(equalTo: bottomAnchor),stackView.leadingAnchor.constraint(equalTo: leadingAnchor),stackView.trailingAnchor.constraint(equalTo: trailingAnchor)])updateSelection()}private func updateSelection() {for (index, button) in buttons.enumerated() {let isSelected = ChartTimeframe.allCases[index] == selectedTimeframebutton.tintColor = isSelected ? .systemBlue : .systemGraybutton.backgroundColor = isSelected ? .systemBlue.withAlphaComponent(0.1) : .clearbutton.layer.cornerRadius = 4}}@objc private func timeframeTapped(_ sender: UIButton) {selectedTimeframe = ChartTimeframe.allCases[sender.tag]}
}

五、架構設計建議

1、分層架構設計:

┌───────────────────────────────┐
│           UI Layer            │
│  - Chart Views (UIKit/SwiftUI)│
│  - Gesture Handlers           │
│  - View Controllers           │
└──────────────┬────────────────┘│
┌──────────────▼───────────────┐
│         Domain Layer         │
│  - Technical Indicators (MA, │
│    MACD, Bollinger Bands)    │
│  - Data Transformations      │
└──────────────┬───────────────┘│
┌──────────────▼───────────────┐
│         Data Layer           │
│  - Network Service (API)     │
│  - Database (CoreData/Realm) │
│  - Caching Mechanism         │
└──────────────────────────────┘

UI Layer:包含圖表視圖(UIKit/SwiftUI)、手勢處理程序和視圖控制器。
Domain Layer:包含技術指標(如MA、MACD、布林帶)和數據轉換。
Data Layer:包含網絡服務(API)、數據庫(CoreData/Realm)和緩存機制。
它們之間的關系是:UI層依賴于領域層,領域層依賴于數據層。

2、性能優化總結表:

優化點技術方案適用場景
大數據量分頁加載 + 增量渲染歷史數據加載
實時更新差異更新 + 增量繪制實時行情
復雜指標后臺計算 + 緩存結果MACD/布林帶等
流暢交互離屏渲染 + GPU加速手勢縮放平移
內存優化對象復用 + 惰性加載移動設備限制

3、跨平臺適配方案:

#if os(iOS)
import UIKit
typealias ViewRepresentable = UIView
#elseif os(macOS)
import AppKit
typealias ViewRepresentable = NSView
#endifclass CrossPlatformChartView: ViewRepresentable {#if os(iOS)override init(frame: CGRect) {super.init(frame: frame)commonInit()}#elseif os(macOS)override init(frame frameRect: NSRect) {super.init(frame: frameRect)commonInit()}#endifprivate func commonInit() {// 共享初始化代碼}#if os(iOS)override func draw(_ rect: CGRect) {super.draw(rect)drawContent()}#elseif os(macOS)override func draw(_ dirtyRect: NSRect) {super.draw(dirtyRect)drawContent()}#endifprivate func drawContent() {// 共享繪制邏輯}
}

六、推薦方案選擇

1、根據需求選擇方案

需求場景推薦方案理由
簡單展示SwiftUI + Canvas開發快,代碼簡潔
復雜交互UIKit + Core Graphics性能好,控制精細
多技術指標Charts 第三方庫內置多種指標實現
跨平臺SwiftUI + 條件編譯支持iOS/macOS
實時行情Core Animation高效增量更新

2、性能對比表

方案10K數據點渲染手勢流暢度內存占用開發效率
Core Graphics300ms???????
SwiftUI Canvas800ms????????
Charts 庫500ms????中高?????
Core Animation100ms????????

最終建議

  1. 對于專業交易應用,使用 Core Graphics + 自定義手勢 實現最佳性能和體驗
  2. 對于普通金融應用,使用 Charts 庫 快速實現豐富功能
  3. 對于 SwiftUI 項目,使用 Canvas + 異步繪制 平衡性能與開發效率

股票圖的實現需要平衡性能、功能和用戶體驗。建議從簡單實現開始,逐步添加技術指標和交互功能,同時做好性能監控和優化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91415.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91415.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91415.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【unitrix】 6.4 數特征(number.rs)

一、源碼 這段代碼定義了一個名為Number的trait&#xff08;特質&#xff09;以及它的實現。 use crate::sealed::Sealed; use crate::number::{V, BaseNumber, TNumber};/// 數值的統一標記特質 /// 可以是編譯時類型化數字(TNumber)或運行時變量(V<T>) pub trait Numbe…

AI治AI:大語言模型自檢新法

“以火攻火”的思路解決大語言模型(LLMs)“幻覺”問題 虛構是由于與提示無關的內部因素而不可預測地從 LLM 中出現的幻覺。作者專注于衡量 LLM 對提示響應的不確定性,使用高不確定性表示虛構的假設。他們通過計算一個稱為熵的量來估計這種不確定性**,熵可以被認為是模型生…

ESLint 配置錯誤:ReferenceError: prettier is not defined 解決方案

問題描述在使用 pnpm lint 運行 ESLint 時&#xff0c;出現以下錯誤&#xff1a;Oops! Something went wrong! :( ESLint: 9.31.0 ReferenceError: prettier is not defined該錯誤導致 ESLint 無法正確執行代碼格式檢查&#xff0c;但 不會影響項目的實際運行&#xff08;如 pn…

數據結構--準備知識

一.算法效率算法效率分為兩種&#xff1a;第一種為時間效率&#xff0c;第二種為空間效率。時間效率稱為時間復雜度&#xff0c;空間效率稱為空間復雜度。時間復雜主要衡量一個算法的運行速度&#xff0c;空間復雜度主要衡量一個算法所需的 額外的空間&#xff08;現在不需要特…

HTML 入門教程:從零開始學習網頁開發基礎

一、HTML簡介 1.1 什么是HTML&#xff1f; HTML全稱是Hyper Text Markup Language&#xff08;超文本標記語言&#xff09;&#xff0c;由Tim Berners-Lee和同事Daniel W. Connolly于1990年創立。它是一種用于創建網頁的標準標記語言&#xff0c;而不是編程語言。 1.2 HTML的…

使用 bat 批量創建帶有項目前綴名的文件夾結構

在項目管理中&#xff0c;經常需要為每個新項目創建一套標準化的文件夾結構。如文檔中所述&#xff0c;用戶希望為每個項目&#xff08;如"Project 1"、“Project 2”&#xff09;創建以下結構的文件夾&#xff1a; project-1_export\project-1_DWG project-1_expo…

Python類中魔術方法(Magic Methods)完全指南:從入門到精通

文章目錄Python類中魔術方法(Magic Methods)完全指南&#xff1a;從入門到精通一、魔術方法基礎1. 什么是魔術方法&#xff1f;2. 魔術方法的特點二、常用魔術方法分類詳解1. 對象創建與初始化2. 對象表示與字符串轉換3. 比較運算符重載4. 算術運算符重載5. 容器類型模擬6. 上下…

H3CNE綜合實驗之五角星

H3CNE綜合實驗之五角星 實驗拓撲圖交換機地址規劃表&#xff1a;SW6G1/0/1Vlan100:10.1.3.2/24G1/0/2Vlan90:10.1.4.2/24G1/0/3Vlan50:10.1.5.1/24G1/0/4Vlan60&#xff1a;10.1.6.1/24SW7G1/0/1Vlan50:10.1.5.2/24G1/0/2Vlan30:192.168.3.1/24G1/0/6Vlan70:10.1.1.2/24G1/0/3-…

Android EventBus使用方法與底層原理詳解

EventBus 是什么&#xff1f; EventBus 是一個基于發布/訂閱&#xff08;Publish/Subscribe&#xff09; 模式的開源庫&#xff08;主要由 greenrobot 開發維護&#xff09;。它的核心目的是簡化 Android 應用中不同組件&#xff08;如 Activity, Fragment, Service, Thread 等…

初等數論簡明教程

初等數論簡明教程 本文給出初等數論中的一些重要的定理與例題&#xff0c;證明風格采用 整除線法 與 命題節點法。 整除線法 指推理的第 nnn 步左邊的字符可由前面左邊的字符得到&#xff0c;右邊的字符可由前面右邊的字符得到&#xff0c;整除線變成了推理線&#xff0c;既少…

Spring之核心容器(IoC,DI,基本操作)詳解

Spring之核心容器IoC/DI/基本操作詳解一、核心概念&#xff1a;IoC與DI的本質1.1 IoC&#xff08;Inversion of Control&#xff0c;控制反轉&#xff09;傳統開發模式&#xff08;無IoC&#xff09;IoC模式&#xff08;Spring容器管理&#xff09;1.2 DI&#xff08;Dependenc…

【論文閱讀】基于注意力機制的冥想腦電分類識別研究(2025)

基于注意力機制的冥想腦電分類識別研究&#x1f4a1; Meta DataTitle基于注意力機制的冥想腦電分類識別研究Authors周梓涵Pub. date2025&#x1f4dc; Research Background & Objective背景&#xff1a; 現代生活壓力導致心理問題日益突出&#xff0c;冥想作為一種有效的心…

GitHub 上 Star 數量前 8 的開源 Web 應用項目

原文鏈接&#xff1a;https://www.nocobase.com/cn/blog/github-open-source-web-applications。 近期&#xff0c;我們發布了多篇「Top GitHub Star 開源項目推薦」系列文章&#xff0c;受到了大量點贊與收藏&#xff0c;很多開發者留言表示希望能看到更多不同領域的開源工具推…

FATFS文件系統原理及其移植詳解

一、FATFS簡介 FATFS 是一個完全免費開源的 FAT/exFAT 文件系統模塊&#xff0c;專門為小型的嵌入式系統而設計。它完全用標準 C 語言&#xff08;ANSI C C89&#xff09;編寫&#xff0c;所以具有良好的硬件平臺獨立性&#xff0c;只需做簡單的修改就可以移植到 8051、PIC、A…

KubeRay 和 Ray

KubeRay 和 Ray 不是替代關系&#xff0c;而是互補的協作關系。兩者在分布式計算生態中扮演不同角色&#xff0c;共同構成完整的云原生 AI 解決方案。以下是具體分析&#xff1a;&#x1f527; 1. 核心定位差異Ray 是分布式計算引擎&#xff0c;提供底層 API&#xff08;如 ray…

破解輪胎倉儲高密度與柔性管理難題

輪胎作為特殊的大件異形工業品&#xff0c;其倉儲管理長期面臨多重挑戰&#xff1a;規格型號繁雜導致SKU數量龐大&#xff0c;重型載重對貨架承重提出極高要求&#xff0c;橡膠材質對防壓變形、避光防老化等存儲環境存在嚴苛標準。傳統平置堆垛或普通貨架方案不僅空間利用率不足…

EVA series系列(上)

目錄 一、EVA 1、概述 2、方法 二、EVA-02 1、概述 2、架構 三、EVA-CLIP 1、概述 2、方法 四、EMU 1、概述 2、架構 3、訓練細節 4、評估 一、EVA 1、概述 為探尋大規模表征學習任務的MIM預訓練任務在ViT基礎上擴展到1B參數量規模&#xff0c;結合10M級別&am…

ABP VNext + EF Core 二級緩存:提升查詢性能

ABP VNext EF Core 二級緩存&#xff1a;提升查詢性能 &#x1f680; &#x1f4da; 目錄ABP VNext EF Core 二級緩存&#xff1a;提升查詢性能 &#x1f680;引言 &#x1f680;一、環境與依賴 &#x1f6e0;?二、集成步驟 ??2.1 安裝 NuGet 包2.2 注冊緩存服務與攔截器2…

3.1k star!推薦一款開源基于AI實現的瀏覽器自動化插件工具 !

大家好&#xff01;今天&#xff0c;我要給大家介紹一款超實用的開源工具——Chrome MCP Server&#xff01;這款工具不僅能大幅提升我們的工作效率&#xff0c;還能讓AI助手&#xff08;如Claude&#xff09;直接操控瀏覽器&#xff0c;實現自動化操作、內容分析等強大功能。 …

關于 OpenAI 的反思

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…