主頁 > 後端開發 > orangepi 4B利用python3使用snowboy實作語音喚醒以及使用騰訊AI api實作語音識別、回復以及合成

orangepi 4B利用python3使用snowboy實作語音喚醒以及使用騰訊AI api實作語音識別、回復以及合成

2020-10-02 10:05:30 後端開發

orangepi 4B利用python3使用snowboy實作語音喚醒以及使用騰訊AI api實作語音識別、回復以及合成

  • 一個月來經歷無數個坑,終于完成教程,整理不易,轉載請注明出處,謝謝
  • 準備作業
    • 基本知識與儲備
    • 硬體方面準備
      • 準備材料
      • 鏡像下載地址
      • 鏡像安裝方法
    • 軟體方面準備
      • 騰訊AI開放平臺注冊開發者
      • 仔細查看開發檔案以及完成應用創建
  • 正式開始操作
    • 登錄以及環境配置
      • 切換中文環境以及安裝中文輸入法
      • 時區設定與中文支持
    • python3安裝及snowboy編譯
      • 安裝python3以及pip3
      • 安裝portaudio、pyaudio以及其他python3的支持包(重點,不安裝無法使用pyaudio,更無法使用語音識別)
      • 安裝swig以及ATLAS依賴
      • 獲取snowboySDK以及snowboy的編譯(注:4B需要修改的地方是重點否則無法完成編譯)
    • 利用騰訊AI api完成語音識別,回復,以及語音合成
      • 用到的python模塊以及引數設定
      • 用來生成需要位數的隨機字符
      • 介面鑒權撰寫
      • 利用wave模塊保存錄音
      • 使用pyaudio錄音
      • 使用pyaudio播放
      • 語音識別
      • 得到回答
      • 語音合成
    • 測驗snowboy以及修改demo
      • 測驗snowboy熱詞喚醒功能
      • 修改Demo
  • 后續延伸
    • 語音控制智能機器人
    • 語音控制家庭智能家居中心

一個月來經歷無數個坑,終于完成教程,整理不易,轉載請注明出處,謝謝

準備作業

基本知識與儲備

1.python基本語法、模塊庫的呼叫、常用模塊熟練呼叫
2.Linux環境的使用,熟悉apt,pip,git下載,python3環境配置
3.一顆能堅持下來的耐心
4.遇到問題能主動去找百度,而不是放棄

硬體方面準備

準備材料

一張16Gclass10SD卡、一個USB2.0或3.0的讀卡器、一個orangepi4B主板、一個USB麥克風(淘寶10塊還包郵那種)、一個支持AUX音響(沒有可以用耳機代替)、一個支持HDMI的顯示幕、一個鍵盤、一個滑鼠以及一個USB擴展塢
下面是我準備的SD卡以及讀卡器
在這里插入圖片描述

鏡像下載地址

我使用的是香橙派官方ubuntu-npu鏡像地址:香橙派官網.
選擇下載用戶手冊和原理圖在檔案中找到這個檔案OrangePi_4_ubuntu_bionic_desktop_linux4.4.179_npu_v1.3.tar.gz
也可以直接在這個鏈接下載: https://pan.baidu.com/s/17549ZGbNTLuJANoiJAA7JQ 提取碼: sja5
同時下載官方工具包找到Win32DiskImager以及SDFormatter或者百度自行下載
Win32DiskImagerSDFormatter

鏡像安裝方法

首先使用SDFormatter將SD卡格式化(這里請備份好自己的資料)第一步
格式化完成
接下來使用Win32DiskImager寫入鏡像到SD卡
寫入鏡像到SD卡
等待提示完成,拔出SD卡,插入opi4b卡槽插上顯示幕鍵盤滑鼠然后插上電源開機,先使用賬號為root密碼為orangepi登錄root登錄
打開LX終端
打開終端

使用install_to_emmc命令將鏡像燒錄至emmc(期間會提示輸入一次Y)

在這里插入圖片描述

提示燒錄完成執行reboot命令重啟香橙派,同時拔出SD卡
至此完成鏡像燒錄以及準備作業

軟體方面準備

騰訊AI開放平臺注冊開發者

很簡單,百度一大堆,自己也可以摸索,這里就不贅述了

仔細查看開發檔案以及完成應用創建

###################################################

正式開始操作

登錄以及環境配置

切換中文環境以及安裝中文輸入法

打開LX終端執行sudo apt-get install ttf-wqy-zenhei安裝中文字庫
執行sudo apt-get install fcitx fcitx-googlepinyin fcitx-module-cloudpinyin fcitx-sunpinyin
安裝中文輸入法
然后重啟就可以看到輸入法安裝完成(中英文切換方式為)

時區設定與中文支持

在LX終端設定上海時間
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
中文環境設定, 打開終端, 輸入以下命令
sudo dpkg-reconfigure locales
語言配置界面
然后往下找(鍵盤-按下鍵) , 在較后面, 找到 en_US.UTF-8 UTF-8,zh_CN.UTF-8 UTF-8,zh_CN.GBK GBK 如上圖所示,按空格選中, 按回車確定,
然后來到如下界面, 選擇 zh_CN.UTF-8, 確定, 按下回車鍵,
選擇中文
出現如下資訊, 配置完成,重啟系統即可,
完成

python3安裝及snowboy編譯

安裝python3以及pip3

終端執行

sudo apt-get install python3 python3-pip3

安裝portaudio、pyaudio以及其他python3的支持包(重點,不安裝無法使用pyaudio,更無法使用語音識別)

終端執行

sudo apt-get install portaudio19-dev python-all-dev python3-all-dev jackd1 portaudio19-doc jack-tools meterbridge liblo-dev
sudo apt-get install pyaudio

安裝swig以及ATLAS依賴

終端執行

sudo apt-get install swig
sudo apt-get install libatlas-base-dev

獲取snowboySDK以及snowboy的編譯(注:4B需要修改的地方是重點否則無法完成編譯)

終端執行

git clone https://github.com/Kitt-AI/snowboy.git

需要修改的地方①在snowboy/swig/Python3中的makefile
找到下圖中位置將ubuntu64替換為aarch64-ubuntu1604
修改1
地方②在snowboy/examples/Python3中的snowboydecoder.py檔案
將from * import snowboydetect 修改為import snowboydetect
在這里插入圖片描述
在snowboy/swig/Python3檔案夾打開終端執行make
至此snowboy編譯完成,

利用騰訊AI api完成語音識別,回復,以及語音合成

用到的python模塊以及引數設定

import base64
import json
import operator
import random
import time
import wave
from urllib import parse
import hashlib
import snowboydecoder
import signal
from contextlib import contextmanager
import requests
from pyaudio import PyAudio, paInt16
CHUNK = 1024  # wav檔案是由若干個CHUNK組成的,CHUNK我們就理解成資料包或者資料片段,
FORMAT = paInt16  # 表示我們使用量化位數 64位來進行錄音
CHANNELS = 1  # 代表的是聲道,1是單聲道,2是雙聲道,
RATE = 16000  # 采樣率 一秒內對聲音信號的采集次數,常用的有8kHz, 16kHz, 32kHz, 48kHz,11.025kHz, 22.05kHz, 44.1kHz,
RECORD_SECONDS = 5  # 錄制時間這里設定了5秒
app_id = '你的appid' # 從開發者平臺得到
appkey = '你的appkey ' # 從開發者平臺得到

用來生成需要位數的隨機字符

def roda(num):
    a = ''
    for i in range(0, num):
        a = a + random.choice('abcdefghijklmnopqrstuvwxyz123456789')
    return a

介面鑒權撰寫

官方解釋
用于計算簽名的引數在不同介面之間會有差異,但演算法程序固定如下4個步驟,
1…將<key, value>請求引數對按key進行字典升序排序,得到有序的引數對串列N
2.將串列N中的引數對按URL鍵值對的格式拼接成字串,得到字串T(如:key1=value1&key2=value2),URL鍵值拼接程序value部分需要URL編碼,URL編碼演算法用大寫字母,例如%E8,而不是小寫%e8
3.將應用密鑰以app_key為鍵名,組成URL鍵值拼接到字串T末尾,得到字串S(如:key1=value1&key2=value2&app_key=密鑰)
4.對字串S進行MD5運算,將得到的MD5值所有字符轉換成大寫,得到介面請求簽名
實際撰寫

def sortDict(data):
    return dict(sorted(data.items(), key=operator.itemgetter(0), reverse=False))

def getReqSign(params, appkey):
    # 1. 字典升序排序
    params1=sortDict(params)
    # 2. 拼按URL鍵值對
    str1 = parse.urlencode(params1)
    # 3. 拼接app_key
    str1 = str1 + '&' + 'app_key=' + appkey
    # 4. MD5運算并轉換大寫,回傳請求簽名
    m = hashlib.md5()
    m.update(str1.encode())
    str_md5 = m.hexdigest()
    return str_md5.upper()

利用wave模塊保存錄音

def save_wave_file(pa, filename, data):
    wf = wave.open(filename, 'wb')
    wf.setnchannels(1)
    wf.setsampwidth(pa.get_sample_size(paInt16))
    wf.setframerate(16000)
    print(type(data))
    wf.writeframes(b"".join(data))
    wf.close()

使用pyaudio錄音

def get_audio(filepath):  # 錄音實作
    print("請開始說話:")  # 提示文本
    pa = PyAudio()
    stream = pa.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK)
    print("*" * 10, "開始錄音:請在5秒內輸入語音")
    frames = []  # 定義一個串列
    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):  # 回圈,采樣率 44100 / 1024 * 5
        data = stream.read(CHUNK)  # 讀取chunk個位元組 保存到data中
        frames.append(data)  # 向串列frames中添加資料data吃
    print("*" * 10, "錄音結束\n")
    stream.stop_stream()
    stream.close()  # 關閉
    pa.terminate()  # 終結
    save_wave_file(pa, filepath, frames)

使用pyaudio播放


def play(fname):
    ding_wav = wave.open(fname, 'rb')
    ding_data = ding_wav.readframes(ding_wav.getnframes())
    with no_alsa_error():
        audio = PyAudio()
    stream_out = audio.open(
        format=audio.get_format_from_width(ding_wav.getsampwidth()),
        channels=ding_wav.getnchannels(),
        rate=ding_wav.getframerate(), input=False, output=True)
    stream_out.start_stream()
    stream_out.write(ding_data)
    time.sleep(0.2)
    stream_out.stop_stream()
    stream_out.close()
    audio.terminate()

語音識別

1.請求引數

引數名稱是否必選資料型別資料約束示例資料描述
app_idint正整數1000001應用標識(AppId)
time_stampint正整數1493468759請求時間戳(秒級)
nonce_strstring非空且長度上限32位元組fa577ce340859f9fe隨機字串
signstring非空且長度固定32位元組簽名資訊,詳見介面鑒權
format 是int正整數2語音壓縮格式編碼,定義見下文描述
speechstring語音資料的Base64編碼,非空且長度上限8MB待識別語音(時長上限15s)
rateint正整數16000語音采樣率編碼,定義見下文描述,(不傳)默認即16KHz

語音壓縮格式編碼

格式名稱格式編碼
PCM1
WAV2
AMR3
SILK4

語音采樣率編碼

采樣率編碼
8KHz8000
16KHz16000

2. 回應引數

引數名稱是否必選資料型別描述
retint回傳碼; 0表示成功,非0表示出錯
msgstring回傳資訊;ret非0時表示出錯時錯誤原因
dataobject回傳資料;ret為0時有意義
+ formatintAPI請求中的格式編碼
+ rateintAPI請求中的采樣率編碼
+ textstring語音識別結果(UTF-8編碼)

撰寫示例

def get_text():
    get_audio('ceshi.wav') # 錄音
    fwave = open('ceshi.wav', mode='rb').read() # 打開錄音檔案
    base64Wav = base64.b64encode(fwave).decode('utf8') # 進行編碼(騰訊api要求base64編碼)
    params = {'app_id': app_id,
     		  'format': '2', 
    		  'rate': '16000',  
              'speech': base64Wav,     # base64編碼的語音資料
              'time_stamp': int(time.time()),  # 時間戳
              'nonce_str': roda(10)}
    params['sign'] = getReqSign(params, appkey) # 得到介面鑒權
    # print(params)
    url = 'https://api.ai.qq.com/fcgi-bin/aai/aai_asr'
    resp = requests.post(url, params)  # post請求
    return json.loads(resp.text).get('data').get('text') #回傳識別到的文本

得到回答

1. 請求引數

引數名稱是否必選資料型別資料約束示例資料描述
app_idint正整數1000001應用標識(AppId)
time_stampint正整數1493468759請求時間戳(秒級)
nonce_strstring非空且長度上限32位元組fa577ce340859f9fe隨機字串
signstring非空且長度固定32位元組簽名資訊,詳見介面鑒權
sessionstringUTF-8編碼,非空且長度上限32位元組10000會話標識(應用內唯一)
questionstringUTF-8編碼,非空且長度上限300位元組你叫啥用戶輸入的聊天內容

2. 回應引數

引數名稱是否必選資料型別描述
retint回傳碼; 0表示成功,非0表示出錯
msgstring回傳資訊;ret非0時表示出錯時錯誤原因
dataobject回傳資料;ret為0時有意義
sessionstringUTF-8編碼,非空且長度上限32位元組
answerstringUTF-8編碼,非空

撰寫示例

def get_chat_text(text):  # 得到回答
    paramsd = {
        'app_id': app_id,
        'session': '10000',
        'question': text,    # 問題文本
        'time_stamp': int(time.time()),
        'nonce_str': roda(17),
    }
    paramsd['sign'] = getReqSign(paramsd, appkey)
    urld = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat'
    respd = requests.post(urld, paramsd)
    return json.loads(respd.text).get('data').get('answer')  # 回傳回答文本

語音合成

1. 請求引數

引數名稱是否必選資料型別資料約束示例資料描述
app_idint正整數1000001應用標識(AppId)
time_stampint正整數1493468759請求時間戳(秒級)
nonce_strstring非空且長度上限32位元組fa577ce340859f9fe隨機字串
signstring非空且長度固定32位元組簽名資訊,詳見介面鑒權
speakerint正整數1語音發音人編碼,定義見下文描述
formatint正整數2合成語音格式編碼,定義見下文描述
volumeint[-10, 10]0合成語音音量,取值范圍[-10, 10],如-10表示音量相對默認值小10dB,0表示默認音量,10表示音量相對默認值大10dB
speedint[50, 200]100合成語音語速,默認100
textstringUTF-8編碼,非空且長度上限150位元組騰訊,你好!待合成文本
ahtint[-24, 24]0合成語音降低/升高半音個數,即改變音高,默認0
apcint[0, 100]58控制頻譜翹曲的程度,改變說話人的音色,默認58

語音發音人編碼

發音人編碼
普通話男聲1
靜琪女聲5
歡馨女聲6
碧萱女聲7

合成語音格式編碼

格式名稱編碼
PCM1
WAV2
MP33

2. 回應引數

引數名稱是否必選資料型別描述
retint回傳碼;
msgstring回傳資訊;ret非0時表示出錯時錯誤原因
dataobject回傳資料;ret為0時有意義
+ formatintAPI請求中的格式編碼
+ speechstring合成語音的base64編碼資料
+ md5sumstring合成語音的md5摘要(base64編碼之前)

base64解碼及寫入檔案

def ToFile(voicex, file):
    base64_data = voicex
    ori_image_data = base64.b64decode(base64_data)
    fout = open(file, 'wb')
    fout.write(ori_image_data)
    fout.close()

撰寫示例

def get_voice(text):
    test = {
        'app_id': app_id,
        'speaker': '6',
        'format': '2',
        'volume': '0',
        'speed': '100',
        'text': text,
        'aht': '0',
        'apc': '58',
        'time_stamp': int(time.time()),
        'nonce_str': roda(17),
    }
    test['sign'] = getReqSign(test, appkey)
    url2 = 'https://api.ai.qq.com/fcgi-bin/aai/aai_tts'
    resp2 = requests.post(url2, test)
    voicex=json.loads(resp2.text).get('data').get('speech')
    ToFile(str(voicex), 'audio.txt')
    ToFile(voicex, 'audio.mp3')
    return 'audio.mp3'

測驗snowboy以及修改demo

測驗snowboy熱詞喚醒功能

終端打開目錄 snowboy/examples/Python3

     cd  snowboy/examples/Python3

開始運行,喊一聲snowboy就可以聽到叮的一聲

    python3 demo.py resources/models/snowboy.umdl

修改Demo

interrupted = False

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

def interrupt_callback():
    global interrupted
    return interrupted

# 回呼函式,語音識別在這里實作,修改也是在這里
def callbacks():
    global detector
    time.sleep(0.2)
    your_text=['哎,我在,你說','我來啦,我來啦,我來啦~','我是你的語音助手小貝']
    a=random.randint(1,3)
    print('小貝'+your_text[a])
    play('huda/xiaobeihuida'+ str(a) +'.wav')  # 為喚醒詞事先準備好的回答
    time.sleep(0.2)
    try:
        a = get_text()
        if a =='嗯' or '':
            continue
        print('你:'+a)
        b =get_chat_text(a)
        print('小貝:'+b)
        c = get_voice(b)
        play(c)
    except Exception:
        print('exception happened...')


@contextmanager
def no_alsa_error():
    try:
        asound = cdll.LoadLibrary('libasound.so')
        asound.snd_lib_error_set_handler(c_error_handler)
        yield
        asound.snd_lib_error_set_handler(None)
    except:
        yield
        pass


def wake_up():
    global detector
    model = 'xiaobeixiaobei.pmdl'  # 我的喚醒詞為 小貝小貝
    # 終止方法為ctrl+c
    signal.signal(signal.SIGINT, signal_handler)
    # 喚醒詞檢測函式,調整sensitivity引數可修改喚醒詞檢測的準確性
    detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
    print('正在聆聽... 請說喚醒詞:小貝小貝')
    # main loop
    # 回呼函式 detected_callback=snowboydecoder.play_audio_file
    # 修改回呼函式可實作我們想要的功能
    detector.start(detected_callback=callbacks,  # 自定義回呼函式
                   interrupt_check=interrupt_callback,
                   sleep_time=0.03)
    # 釋放資源
    detector.terminate()
#程式入口
if __name__ == "__main__":
    wake_up()

后續延伸

修改回呼函式可以完成更多作業

語音控制智能機器人

與arduino使用uart通信可實作智能控制機器人
等待后續更新
已經更新傳送門

語音控制家庭智能家居中心

加入mqtt可以作為語音控制家庭智能家居中心
等待后續更新

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

標籤:python

上一篇:基于基因資料的神經網路模式分類研究

下一篇:縱橫美國思維導圖學習

標籤雲
其他(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