主頁 > 後端開發 > laravel 學習筆記 —— 神奇的服務容器

laravel 學習筆記 —— 神奇的服務容器

2021-01-24 17:45:15 後端開發

本文轉載至:https://www.insp.top/learn-laravel-container

laravel 學習筆記 —— 神奇的服務容器

竟然有人認為我是抄 Laravel 學院的,心塞,世界觀已崩塌,

容器,字面上理解就是裝東西的東西,常見的變數、物件屬性等都可以算是容器,一個容器能夠裝什么,全部取決于你對該容器的定義,當然,有這樣一種容器,它存放的不是文本、數值,而是物件、物件的描述(類、介面)或者是提供物件的回呼,通過這種容器,我們得以實作許多高級的功能,其中最常提到的,就是 “解耦” 、“依賴注入(DI)”,本文就從這里開始,

IoC 容器, laravel 的核心

Laravel 的核心就是一個 IoC 容器,根據檔案,稱其為“服務容器”,顧名思義,該容器提供了整個框架中需要的一系列服務,作為初學者,很多人會在這一個概念上犯難,因此,我打算從一些基礎的內容開始講解,通過理解面向物件開發中依賴的產生和解決方法,來逐漸揭開“依賴注入”的面紗,逐漸理解這一神奇的設計理念,

本文一大半內容都是通過舉例來讓讀者去理解什么是 IoC(控制反轉)DI(依賴注入),通過理解這些概念,來更加深入,更多關于 laravel 服務容器的用法建議閱讀檔案即可,

IoC 容器誕生的故事

講解 IoC 容器有很多的文章,我之前也寫過,但現在我打算利用當下的靈感重新來過,那么開始吧,

超人和超能力,依賴的產生!

面向物件編程,有以下幾樣東西無時不刻的接觸:介面還有物件,這其中,介面是類的原型,一個類必須要遵守其實作的介面;物件則是一個類實體化后的產物,我們稱其為一個實體,當然這樣說肯定不利于理解,我們就實際的寫點中看不中用的代碼輔助學習,

怪物橫行的世界,總歸需要點超級人物來擺平,

我們把一個“超人”作為一個類,

class Superman {}

我們可以想象,一個超人誕生的時候肯定擁有至少一個超能力,這個超能力也可以抽象為一個物件,為這個物件定義一個描述他的類吧,一個超能力肯定有多種屬性、(操作)方法,這個盡情的想象,但是目前我們先大致定義一個只有屬性的“超能力”,至于能干啥,我們以后再豐富:

class Power {
    /**
     * 能力值
     */
    protected $ability;

    /**
     * 能力范圍或距離
     */
    protected $range;

    public function __construct($ability, $range)
    {
        $this->ability = $ability;
        $this->range = $range;
    }
}

這時候我們回過頭,修改一下之前的“超人”類,讓一個“超人”創建的時候被賦予一個超能力:

class Superman
{
    protected $power;

    public function __construct()
    {
        $this->power = new Power(999, 100);
    }
}

這樣的話,當我們創建一個“超人”實體的時候,同時也創建了一個“超能力”的實體,但是,我們看到了一點,“超人”和“超能力”之間不可避免的產生了一個依賴,

所謂“依賴”,就是 “我若依賴你,我就不能離開你”,

在一個貫徹面向物件編程的專案中,這樣的依賴隨處可見,少量的依賴并不會有太過直觀的影響,我們隨著這個例子逐漸鋪開,讓大家慢慢意識到,當依賴達到一個量級時,是怎樣一番噩夢般的體驗,當然,我也會自然而然的講述如何解決問題,

一堆亂麻 —— 可怕的依賴

之前的例子中,超能力類實體化后是一個具體的超能力,但是我們知道,超人的超能力是多元化的,每種超能力的方法、屬性都有不小的差異,沒法通過一種類描述完全,我們現在進行修改,我們假設超人可以有以下多種超能力:

  • 飛行,屬性有:飛行速度、持續飛行時間
  • 蠻力,屬性有:力量值
  • 能量彈,屬性有:傷害值、射擊距離、同時射擊個數

我們創建了如下類:

class Flight
{
    protected $speed;
    protected $holdtime;
    public function __construct($speed, $holdtime) {}
}

class Force
{
    protected $force;
    public function __construct($force) {}
}

class Shot
{
    protected $atk;
    protected $range;
    protected $limit;
    public function __construct($atk, $range, $limit) {}
}

*為了省事兒我沒有詳細寫出 __construct() 這個建構式的全部,只寫了需要傳遞的引數,

好了,這下我們的超人有點“忙”了,在超人初始化的時候,我們會根據需要來實體化其擁有的超能力嗎,大致如下:

class Superman
{
    protected $power;

    public function __construct()
    {
        $this->power = new Fight(9, 100);
        // $this->power = new Force(45);
        // $this->power = new Shot(99, 50, 2);
        /*
        $this->power = array(
            new Force(45),
            new Shot(99, 50, 2)
        );
        */
    }
}

我們需要自己手動的在建構式內(或者其他方法里)實體化一系列需要的類,這樣并不好,可以想象,假如需求變更(不同的怪物橫行地球),需要更多的有針對性的 新的 超能力,或者需要 變更 超能力的方法,我們必須 重新改造 超人,*換句話說就是,改變超能力的同時,我還得重新制造個超人*,效率太低了!新超人還沒創造完成世界早已被毀滅,

這時,靈機一動的人想到:為什么不可以這樣呢?超人的能力可以被隨時更換,只需要添加或者更新一個芯片或者其他裝置啥的(想到鋼鐵俠沒),這樣的話就不要整個重新來過了,

對,就是這樣的,

我們不應該手動在 “超人” 類中固化了他的 “超能力” 初始化的行為,而轉由外部負責,由外部創造超能力模組、裝置或者芯片等(我們后面統一稱為 “模組”),植入超人體內的某一個介面,這個介面是一個既定的,只要這個 “模組” 滿足這個介面的裝置都可以被超人所利用,可以提升、增加超人的某一種能力,這種由外部負責其依賴需求的行為,我們可以稱其為 “控制反轉(IoC)”,

工廠模式,依賴轉移!

當然,實作控制反轉的方法有幾種,在這之前,不如我們先了解一些好玩的東西,

我們可以想到,組件、工具(或者超人的模組),是一種可被生產的玩意兒,生產的地方當然是 “工廠(Factory)”,于是有人就提出了這樣一種模式: 工廠模式

工廠模式,顧名思義,就是一個類所依賴的外部事物的實體,都可以被一個或多個 “工廠” 創建的這樣一種開發模式,就是 “工廠模式”,

我們為了給超人制造超能力模組,我們創建了一個工廠,它可以制造各種各樣的模組,且僅需要通過一個方法:

class SuperModuleFactory
{
    public function makeModule($moduleName, $options)
    {
        switch ($moduleName) {
            case 'Fight':   return new Fight($options[0], $options[1]);
            case 'Force':   return new Force($options[0]);
            case 'Shot':    return new Shot($options[0], $options[1], $options[2]);
        }
    }
}

這時候,超人 創建之初就可以使用這個工廠!

class Superman
{
    protected $power;

    public function __construct()
    {
        // 初始化工廠
        $factory = new SuperModuleFactory;

        // 通過工廠提供的方法制造需要的模塊
        $this->power = $factory->makeModule('Fight', [9, 100]);
        // $this->power = $factory->makeModule('Force', [45]);
        // $this->power = $factory->makeModule('Shot', [99, 50, 2]);
        /*
        $this->power = array(
            $factory->makeModule('Force', [45]),
            $factory->makeModule('Shot', [99, 50, 2])
        );
        */
    }
}

可以看得出,我們不再需要在超人初始化之初,去初始化許多第三方類,只需初始化一個工廠類,即可滿足需求,但這樣似乎和以前區別不大,只是沒有那么多 new 關鍵字,其實我們稍微改造一下這個類,你就明白,工廠類的真正意義和價值了,

class Superman
{
    protected $power;

    public function __construct(array $modules)
    {
        // 初始化工廠
        $factory = new SuperModuleFactory;

        // 通過工廠提供的方法制造需要的模塊
        foreach ($modules as $moduleName => $moduleOptions) {
            $this->power[] = $factory->makeModule($moduleName, $moduleOptions);
        }
    }
}

// 創建超人
$superman = new Superman([
    'Fight' => [9, 100], 
    'Shot' => [99, 50, 2]
    ]);

現在修改的結果令人滿意,現在,“超人” 的創建不再依賴任何一個 “超能力” 的類,我們如若修改了或者增加了新的超能力,只需要針對修改 SuperModuleFactory 即可,擴充超能力的同時不再需要重新編輯超人的類檔案,使得我們變得很輕松,但是,這才剛剛開始,

再進一步!IoC 容器的重要組成 —— 依賴注入!

由 “超人” 對 “超能力” 的依賴變成 “超人” 對 “超能力模組工廠” 的依賴后,對付小怪獸們變得更加得心應手,但這也正如你所看到的,依賴并未解除,只是由原來對多個外部的依賴變成了對一個 “工廠” 的依賴,假如工廠出了點麻煩,問題變得就很棘手,

其實大多數情況下,工廠模式已經足夠了,工廠模式的缺點就是:介面未知(即沒有一個很好的契約模型,關于這個我馬上會有解釋)、產生物件型別單一,總之就是,還是不夠靈活,雖然如此,工廠模式依舊十分優秀,并且適用于絕大多數情況,不過我們為了講解后面的 依賴注入 ,這里就先夸大一下工廠模式的缺陷咯,

我們知道,超人依賴的模組,我們要求有統一的介面,這樣才能和超人身上的注入介面對接,最終起到提升超能力的效果,

事實上,我之前說謊了,不僅僅只有一堆小怪獸,還有更多的大怪獸,嘿嘿,額,這時候似乎工廠的生產能力顯得有些不足 —— 由于工廠模式下,所有的模組都已經在工廠類中安排好了,如果有新的、高級的模組加入,我們必須修改工廠類(好比增加新的生產線):

class SuperModuleFactory
{
    public function makeModule($moduleName, $options)
    {
        switch ($moduleName) {
            case 'Fight':   return new Fight($options[0], $options[1]);
            case 'Force':   return new Force($options[0]);
            case 'Shot':    return new Shot($options[0], $options[1], $options[2]);
            // case 'more': .......
            // case 'and more': .......
            // case 'and more': .......
            // case 'oh no! its too many!': .......
        }
    }
}

看到沒,,,噩夢般的感受!

其實靈感就差一步!你可能會想到更為靈活的辦法!對,下一步就是我們今天的主要配角 —— DI (依賴注入)

由于對超能力模組的需求不斷增大,我們需要集合整個世界的高智商人才,一起解決問題,不應該僅僅只有幾個工廠壟斷負責,不過高智商人才們都非常自負,認為自己的想法是對的,創造出的超能力模組沒有統一的介面,自然而然無法被正常使用,這時我們需要提出一種契約,這樣無論是誰創造出的模組,都符合這樣的介面,自然就可被正常使用,

interface SuperModuleInterface
{
    /**
     * 超能力激活方法
     *
     * 任何一個超能力都得有該方法,并擁有一個引數
     *@param array $target 針對目標,可以是一個或多個,自己或他人
     */
    public function activate(array $target);
}

上文中,我們定下了一個介面 (超能力模組的規范、契約),所有被創造的模組必須遵守該規范,才能被生產,

其實,這就是 php 中 介面( interface ) 的用處和意義!很多人覺得,為什么 php 需要介面這種東西?難道不是 java 、 C# 之類的語言才有的嗎?這么說,只要是一個正常的面向物件編程語言(雖然 php 可以面向程序),都應該具備這一特性,因為一個 物件(object) 本身是由他的模板或者原型 —— 類 (class) ,經過實體化后產生的一個具體事物,而有時候,實作統一種方法且不同功能(或特性)的時候,會存在很多的類(class),這時候就需要有一個契約,讓大家撰寫出可以被隨時替換卻不會產生影響的介面,這種由編程語言本身提出的硬性規范,會增加更多優秀的特性,

雖然有些繞,但通過我們接下來的實體,大家會慢慢領會介面帶來的好處,

這時候,那些提出更好的超能力模組的高智商人才,遵循這個介面,創建了下述(模組)類:

/**
 * X-超能量
 */
class XPower implements SuperModuleInterface
{
    public function activate(array $target)
    {
        // 這只是個例子,,具體自行腦補
    }
}

/**
 * 終極炸彈 (就這么俗)
 */
class UltraBomb implements SuperModuleInterface
{
    public function activate(array $target)
    {
        // 這只是個例子,,具體自行腦補
    }
}

同時,為了防止有些 “磚家” 自作聰明,或者一些叛徒惡意搗蛋,不遵守契約胡亂制造模組,影響超人,我們對超人初始化的方法進行改造:

class Superman
{
    protected $module;

    public function __construct(SuperModuleInterface $module)
    {
        $this->module = $module
    }
}

改造完畢!現在,當我們初始化 “超人” 類的時候,提供的模組實體必須是一個 SuperModuleInterface 介面的實作,否則就會提示錯誤,

正是由于超人的創造變得容易,一個超人也就不需要太多的超能力,我們可以創造多個超人,并分別注入需要的超能力模組即可,這樣的話,雖然一個超人只有一個超能力,但超人更容易變多,我們也不怕怪獸啦!

現在有人疑惑了,你要講的 依賴注入 呢?

其實,上面講的內容,正是依賴注入,

什么叫做 依賴注入

本文從開頭到現在提到的一系列依賴,只要不是由內部生產(比如初始化、建構式 __construct 中通過工廠方法、自行手動 new 的),而是由外部以引數或其他形式注入的,都屬于 依賴注入(DI) ,是不是豁然開朗?事實上,就是這么簡單,下面就是一個典型的依賴注入:

// 超能力模組
$superModule = new XPower;

// 初始化一個超人,并注入一個超能力模組依賴
$superMan = new Superman($superModule);

關于依賴注入這個本文的主要配角,也就這么多需要講的,理解了依賴注入,我們就可以繼續深入問題,慢慢走近今天的主角……

更為先進的工廠 —— IoC 容器!

剛剛列了一段代碼:

$superModule = new XPower;

$superMan = new Superman($superModule);

讀者應該看出來了,手動的創建了一個超能力模組、手動的創建超人并注入了剛剛創建超能力模組,呵呵,手動,

現代社會,應該是高效率的生產,干凈的車間,完美的自動化裝配,

一群怪獸來了,如此低效率產出超人是不現實,我們需要自動化 —— 最多一條指令,千軍萬馬來相見,我們需要一種高級的生產車間,我們只需要向生產車間提交一個腳本,工廠便能夠通過指令自動化生產,這種更為高級的工廠,就是工廠模式的升華 —— IoC 容器

class Container
{
    protected $binds;

    protected $instances;

    public function bind($abstract, $concrete)
    {
        if ($concrete instanceof Closure) {
            $this->binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;
        }
    }

    public function make($abstract, $parameters = [])
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        array_unshift($parameters, $this);

        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}

這時候,一個十分粗糙的容器就誕生了,現在的確很簡陋,但不妨礙我們進一步提升他,先著眼現在,看看這個容器如何使用吧!

// 創建一個容器(后面稱作超級工廠)
$container = new Container;

// 向該 超級工廠 添加 超人 的生產腳本
$container->bind('superman', function($container, $moduleName) {
    return new Superman($container->make($moduleName));
});

// 向該 超級工廠 添加 超能力模組 的生產腳本
$container->bind('xpower', function($container) {
    return new XPower;
});

// 同上
$container->bind('ultrabomb', function($container) {
    return new UltraBomb;
});

// ******************  華麗麗的分割線  **********************
// 開始啟動生產
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
$superman_3 = $container->make('superman', ['xpower']);
// ...隨意添加

看到沒?通過最初的 系結(bind) 操作,我們向 超級工廠 注冊了一些生產腳本,這些生產腳本在生產指令下達之時便會執行,發現沒有?我們徹底的解除了 超人 與 超能力模組 的依賴關系,更重要的是,容器類也絲毫沒有和他們產生任何依賴!我們通過注冊、系結的方式向容器中添加一段可以被執行的回呼(可以是匿名函式、非匿名函式、類的方法)作為生產一個類的實體的 腳本 ,只有在真正的 生產(make) 操作被呼叫執行時,才會觸發,

這樣一種方式,使得我們更容易在創建一個實體的同時解決其依賴關系,并且更加靈活,當有新的需求,只需另外系結一個“生產腳本”即可,

實際上,真正的 IoC 容器更為高級,我們現在的例子中,還是需要手動提供超人所需要的模組引數,但真正的 IoC 容器會根據類的依賴需求,自動在注冊、系結的一堆實體中搜尋符合的依賴需求,并自動注入到建構式引數中去,Laravel 框架的服務容器正是這么做的,實作這種功能其實理論上并不麻煩,但我并不會在本文中寫出,因為……我懶得寫,

不過我告訴大家,這種自動搜尋依賴需求的功能,是通過 反射(Reflection) 實作的,恰好的,php 完美的支持反射機制!關于反射,php 官方檔案有詳細的資料,并且中文翻譯基本覆寫,足夠學習和研究!

http://php.net/manual/zh/book.reflection.php

現在,到目前為止,我們已經不再懼怕怪獸們了,高智商人才集思廣益,井井有條,根據介面契約創造規范的超能力模組,超人開始批量產出,最終,人人都是超人,你也可以是哦 stuck_out_tongue_closed_eyes

回歸正常世界,我們開始重新審視 laravel 的核心,

現在,我們開始慢慢解讀 laravel 的核心,其實,laravel 的核心就是一個 IoC 容器,也恰好是我之前所說的高級的 IoC 容器,

可以說,laravel 的核心本身十分輕量,并沒有什么很神奇很實質性的應用功能,很多人用到的各種功能模塊比如 Route(路由)Eloquent ORM(資料庫 ORM 組件)Request and Response(請求和回應)等等等等,實際上都是與核心無關的類模塊提供的,這些類從注冊到實體化,最終被你所使用,其實都是 laravel 的服務容器負責的,

我們以大家最常見的 Route 類作為例子,大家可能經常見到路由定義是這樣的:

Route::get('/', function() {
    // bla bla bla...
});

實際上, Route 類被定義在這個命名空間:Illuminate\Routing\Router,檔案 vendor/laravel/framework/src/Illuminate/Routing/Router.php

我們通過打開發現,這個類的這一系列方法,如 getpostany 等都不是靜態(static)方法,這是怎么一回事兒?不要急,我們繼續,

服務提供者

我們在前文介紹 IoC 容器的部分中,提到了,一個類需要系結、注冊至容器中,才能被“制造”,

對,一個類要被容器所能夠提取,必須要先注冊至這個容器,既然 laravel 稱這個容器叫做服務容器,那么我們需要某個服務,就得先注冊、系結這個服務到容器,那么提供服務并系結服務至容器的東西,就是 服務提供者(ServiceProvider)

雖然,系結一個類到容器不一定非要通過 服務提供者(ServiceProvider)

但是,我們知道,有時候我們的類、模塊會有需要其他類和組件的情況,為了保證初始化階段不會出現所需要的模塊和組件沒有注冊的情況,laravel 將注冊和初始化行為進行拆分,注冊的時候就只能注冊,初始化的時候就是初始化,拆分后的產物就是現在的 服務提供者

服務提供者主要分為兩個部分,register(注冊)boot(引導、初始化),具體參考檔案,register 負責進行向容器注冊“腳本”,但要注意注冊部分不要有對未知事物的依賴,如果有,就要移步至 boot 部分,

Facade

我們現在解答之前關于 Route 的方法為何能以靜態方法訪問的問題,實際上這個問題檔案上有寫,簡單說來就是模擬一個類,提供一個靜態魔術方法__callStatic,并將該靜態方法映射到真正的方法上,

我們使用的 Route 類實際上是 Illuminate\Support\Facades\Route 通過 class_alias() 函式創造的 別名 而已,這個類被定義在檔案 vendor/laravel/framework/src/Illuminate/Support/Facades/Route.php

我們打開檔案一看……誒?怎么只有這么簡單的一段代碼呢?

<?php namespace Illuminate\Support\Facades;

/**
 * @see \Illuminate\Routing\Router
 */
class Route extends Facade {

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'router';
    }

}

其實仔細看,會發現這個類繼承了一個叫做 Facade 的類,到這里謎底差不多要解開了,

上述簡單的定義中,我們看到了 getFacadeAccessor 方法回傳了一個 route,這是什么意思呢?事實上,這個值被一個 ServiceProvider 注冊過,大家應該知道注冊了個什么,當然是那個真正的路由類!

有人會問,Facade 是怎么實作的,我并不想說得太細,一個是我懶,另一個原因就是,自己發現一些東西更容易理解,并不容易忘記,很多細節我已經說了,建議大家自行去研究,

至此,我們已經講的差不多了,

和平!我們該總結總結了!

無論如何,世界和平了,

這里要總結的內容就是,其實很多事情并不復雜,怕的是復雜的理論內容,我覺得很多東西一旦想通也就那么回事兒,很多人覺得 laravel 這不好那不好、這里難哪里難,我只能說,laravel 的確不是一流和優秀的框架,說 laravel 是一流、優秀的框架的人,不是 laravel 的粉絲那么就是跟風炒作,Laravel 最大的特點和優秀之處就是使用了很多 php 比較新(實際上并不新)的概念和技術(也就一堆語法糖)而已,因此 laravel 的確符合一個適宜學習的框架,Laravel 的構思的確和其他框架有很大不同,這也要求學習他的人必須熟練 php,并 基礎扎實!如果你覺得學 laravel 框架十分困難,那么原因只有一個:你 php 基礎不好,

另外,善于利用命名空間和面向物件的諸多特性,去追尋一些東西,你會發現,原來這一切這么容易,

本文寫著很辛苦,希望各位尊重作者原創內容,轉載可以不通知本人但務必保留轉載來源資訊,謝謝!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/251390.html

標籤:PHP

上一篇:PHP中用+號連接陣列的結果是?

下一篇:WEB前端第五十九課——時間戳、資料互動小案例

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more