声明式UI语法

news2024/12/22 17:25:01

一、ArkTS的基本组成

@Entry  // 装饰器
@Component  // 装饰器
struct  Hello {  // 自定义组件
  @State myText: string = 'World';
  build() {  // UI描述
    Column() {  // 系统组件
      Text('Hello ${this.myText}')
        .fontSize(50)
      Divider()
      Button('Click me')
        .onClick(() => {  // 事件方法
          this.myText = 'ArkUI'
        })
        .height(50)  // 属性描述
        .width(100)
        .margin({top: 20})
    }
  }
}

 

  • 装饰器: 用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如上述示例中@Entry、@Component和@State都是装饰器,@Component表示自定义组件,@Entry表示该自定义组件为入口组件,@State表示组件中的状态变量,状态变量变化会触发UI刷新。

  • UI描述:以声明式的方式来描述UI的结构,例如build()方法中的代码块。

  • 自定义组件:可复用的UI单元,可组合其他组件,如上述被@Component装饰的struct Hello。

  • 系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的Column、Text、Divider、Button。

  • 属性方法:组件可以通过链式调用配置多项属性,如fontSize()、width()、height()、backgroundColor()等。

  • 事件方法:组件可以通过链式调用设置多个事件的响应逻辑,如跟随在Button后面的onClick()。

  • 系统组件、属性方法、事件方法具体使用可参考基于ArkTS的声明式开发范式。

二、声明式UI描述

 ArkTS以声明方式组合和扩展组件来描述应用程序的UI,同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。

        1、创建组件

        根据组件构造方法的不同,创建组件包含有参数(如果组件的接口定义包含构造参数,则在组件后面的“()”需要配置相应参数)和无参数(如果组件的接口定义没有包含必选构造参数,则组件后面的“()”不需要配置任何内容)两种方式。

// 无参数
Column() {
  Text('item 1')
  Divider()
  Text('item 2')
}

// 有参数
Image('https://xyz/test.jpg')

// string类型的参数
Text('test')
// $r形式引入应用资源,可应用于多语言场景
Text($r('app.string.title_value'))
// 无参数形式
Text()

        2、配置属性

        属性方法以“.”链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行。

// 配置Text组件的字体大小
Text('test')
  .fontSize(12)

// 配置多个属性
Image('test.jpg')
  .alt('error.jpg')    
  .width(100)    
  .height(100)

// 除了直接传递常量参数外,还可以传递变量或表达式。
Text('hello')
  .fontSize(this.size)
Image('test.jpg')
  .width(this.count % 2 === 0 ? 100 : 200)    
  .height(this.offset + 100)

        3、配置事件

        事件方法以“.”链式调用的方式配置系统组件支持的事件,建议每个事件方法单独写一行。

// 使用箭头函数配置组件的事件方法。
Button('Click me')
  .onClick(() => {
    this.myText = 'ArkUI';
  })

// 使用组件的成员函数配置组件的事件方法,需要bind this。ArkTS语法不推荐使用成员函数配合bind this去配置组件的事件方法。
myClickHandler(): void {
  this.counter += 2;
}
...
Button('add counter')
  .onClick(this.myClickHandler.bind(this))

// 使用声明的箭头函数,可以直接调用,不需要bind this。
fn = () => {
  console.info(`counter: ${this.counter}`)
  this.counter++
}
...
Button('add counter')
  .onClick(this.fn)

        4、配置子组件

        如果组件支持子组件配置,则需在尾随闭包"{...}"中为组件添加子组件的UI描述。Column、Row、Stack、Grid、List等组件都是容器组件。

// 容器组件均支持子组件配置,可以实现相对复杂的多级嵌套。
Column() {
  Row() {
    Image('test1.jpg')
      .width(100)
      .height(100)
    Button('click +1')
      .onClick(() => {
        console.info('+1 clicked!');
      })
  }
}

三、创建自定义组件

在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。

自定义组件具有以下特点:

  • 可组合:允许开发者组合使用系统组件、及其属性和方法。

  • 可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。

  • 数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。

        1、自定义组件的基本结构

        a、struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。自定义组件名、类名、函数名不能和系统组件名相同。

        b、@Component:@Component装饰器仅能装饰struct关键字声明的数据结构。struct被@Component装饰后具备组件化的能力,需要实现build方法描述UI,一个struct只能被一个@Component装饰。@Component可以接受一个可选的bool类型参数。 

@Component
struct MyComponent {
}

        c、build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。

@Component
struct MyComponent {
  build() {
  }
}

        d、@Entry:@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件。

@Entry
@Component
struct MyComponent {
}

        命名路由跳转选项: 

名称类型必填说明
routeNamestring表示作为命名路由页面的名字。
storageLocalStorage页面级的UI状态存储。
useSharedStorage12+boolean是否使用LocalStorage.getShared()接口返回的LocalStorage实例对象,默认值false。
@Entry({ routeName : 'myPage' })
@Component
struct MyComponent {
}

        e、@Reusable:@Reusable装饰的自定义组件具备可复用能力

@Reusable
@Component
struct MyComponent {
}

        2、成员函数/变量

        成员函数约束:自定义组件的成员函数为私有的,且不建议声明成静态函数。

        成员变量约束:自定义组件的成员变量为私有的,且不建议声明成静态变量;自定义组件的成员变量本地初始化有些是可选的,有些是必选的。具体是否需要本地初始化,是否需要从父组件通过参数传递初始化子组件的成员变量,请参考状态管理。

        3、自定义组件参数规定

@Component
struct MyComponent {
  private countDownFrom: number = 0;
  private color: Color = Color.Blue;

  build() {
  }
}

@Entry
@Component
struct ParentComponent {
  private someColor: Color = Color.Pink;

  build() {
    Column() {
      // 创建MyComponent实例,并将创建MyComponent成员变量countDownFrom初始化为10,将成员变量color初始化为this.someColor
      MyComponent({ countDownFrom: 10, color: this.someColor })
    }
  }
}

        下面的示例代码将父组件中的函数传递给子组件,并在子组件中调用。

@Entry
@Component
struct Parent {
  @State cnt: number = 0
  submit: () => void = () => {
    this.cnt++;
  }

  build() {
    Column() {
      Text(`${this.cnt}`)
      Son({ submitArrow: this.submit })
    }
  }
}

@Component
struct Son {
  submitArrow?: () => void

  build() {
    Row() {
      Button('add')
        .width(80)
        .onClick(() => {
          if (this.submitArrow) {
            this.submitArrow()
          }
        })
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .height(56)
  }
}

        4、build函数

        所有声明在build()函数的语句,我们统称为UI描述,UI描述需要遵循以下规则:

        a、@Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点;@Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点。

        b、不允许声明本地变量

        c、不允许在UI描述里直接使用console.info,但允许在方法或者函数里使用

        d、不允许创建本地的作用域

        e、不允许调用没有用@Builder装饰的方法,允许系统组件的参数是TS方法的返回值

        f、不允许使用switch语法,如果需要使用条件判断,请使用if

        g、不允许使用表达式

        h、不允许直接改变状态变量

        在ArkUI状态管理中,状态驱动UI更新。所以,不能在自定义组件的build()或@Builder方法里直接改变状态变量,这可能会造成循环渲染的风险。

        5、 自定义组件通用样式

        自定义组件通过“.”链式调用的形式设置通用样式。

@Component
struct MyComponent2 {
  build() {
    Button(`Hello World`)
  }
}

@Entry
@Component
struct MyComponent {
  build() {
    Row() {
      MyComponent2()
        .width(200)
        .height(300)
        .backgroundColor(Color.Red)
    }
  }
}

四、页面和自定义组件的生命周期

        1、页面生命周期

        即被@Entry装饰的组件生命周期,提供以下生命周期接口:

  • onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。

  • onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景。

  • onBackPress:当用户点击返回按钮时触发。

        2、组件生命周期

        即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:

  • aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。

  • onDidBuild:组件build()函数执行完成之后回调该接口,不建议在onDidBuild函数中更改状态变量、使用animateTo等功能,这可能会导致不稳定的UI表现。

  • aboutToDisappear:aboutToDisappear函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。

 

 3、自定义组件的创建和渲染流程

        a、自定义组件的创建:自定义组件的实例由ArkUI框架创建

        b、初始化自定义组件的成员变量:通过本地默认值或者构造方法传递参数来初始化自定义组件的成员变量,初始化顺序为成员变量的定义顺序

        c、如果开发者定义了aboutToAppear,则执行aboutToAppear方法

        d、在首次渲染的时候,执行build方法渲染系统组件,如果子组件为自定义组件,则创建自定义组件的实例。在首次渲染的过程中,框架会记录状态变量和组件的映射关系,当状态变量改变时,驱动其相关的组件刷新

        e、 如果开发者定义了onDidBuild,则执行onDidBuild方法

        4、自定义组件重新渲染

        当事件句柄被触发(比如设置了点击事件,即触发点击事件)改变了状态变量时,或者LocalStorage / AppStorage中的属性更改,并导致绑定的状态变量更改其值时:

        a、框架观察到了变化,将启动重新渲染。

        b、根据框架持有的两个map,框架可以知道该状态变量管理了哪些UI组件,以及这些UI组件对应的更新函数。执行这些UI组件的更新函数,实现最小化更新。

        5、自定义组件删除

        如果if组件的分支改变,或者ForEach循环渲染中数组的个数改变,组件将被删除:

        a、在删除组件之前,将调用其aboutToDisappear生命周期函数,标记着该节点将要被销毁。ArkUI的节点删除机制是:后端节点直接从组件树上摘下,后端节点被销毁,对前端节点解引用,前端节点已经没有引用时,将被JS虚拟机垃圾回收。

        b、自定义组件和它的变量将被删除,如果其有同步的变量,比如@Link、@Prop、@StorageLink,将从同步源上取消注册。

        不建议在生命周期aboutToDisappear内使用async await,如果在生命周期的aboutToDisappear使用异步操作(Promise或者回调方法),自定义组件将被保留在Promise的闭包中,直到回调方法被执行完,这个行为阻止了自定义组件的垃圾回收。

        展示生命周期被调用的实例:

// Index.ets
import { router } from '@kit.ArkUI';

@Entry
@Component
struct MyComponent {
  @State showChild: boolean = true;
  @State btnColor:string = "#FF007DFF";

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry装饰的组件才可以调用页面的生命周期
  onBackPress() {
    console.info('Index onBackPress');
    this.btnColor ="#FFEE0606";
    return true // 返回true表示页面自己处理返回逻辑,不进行页面路由;返回false表示使用默认的路由返回逻辑,不设置返回值按照false处理
  }

  // 组件生命周期
  aboutToAppear() {
    console.info('MyComponent aboutToAppear');
  }

  // 组件生命周期
  onDidBuild() {
    console.info('MyComponent onDidBuild');
  }

  // 组件生命周期
  aboutToDisappear() {
    console.info('MyComponent aboutToDisappear');
  }

  build() {
    Column() {
      // this.showChild为true,创建Child子组件,执行Child aboutToAppear
      if (this.showChild) {
        Child()
      }
      // this.showChild为false,删除Child子组件,执行Child aboutToDisappear
      Button('delete Child')
      .margin(20)
      .backgroundColor(this.btnColor)
      .onClick(() => {
        this.showChild = false;
      })
      // push到page页面,执行onPageHide
      Button('push to next page')
        .onClick(() => {
          router.pushUrl({ url: 'pages/page' });
        })
    }

  }
}

@Component
struct Child {
  @State title: string = 'Hello World';
  // 组件生命周期
  aboutToDisappear() {
    console.info('[lifeCycle] Child aboutToDisappear')
  }

  // 组件生命周期
  onDidBuild() {
    console.info('[lifeCycle] Child onDidBuild');
  }

  // 组件生命周期
  aboutToAppear() {
    console.info('[lifeCycle] Child aboutToAppear')
  }

  build() {
    Text(this.title)
      .fontSize(50)
      .margin(20)
      .onClick(() => {
        this.title = 'Hello ArkUI';
      })
  }
}

 

// page.ets
@Entry
@Component
struct page {
  @State textColor: Color = Color.Black;
  @State num: number = 0;

  onPageShow() {
    this.num = 5;
  }

  onPageHide() {
    console.log("page onPageHide");
  }

  onBackPress() { // 不设置返回值按照false处理
    this.textColor = Color.Grey;
    this.num = 0;
  }

  aboutToAppear() {
    this.textColor = Color.Blue;
  }

  build() {
    Column() {
      Text(`num 的值为:${this.num}`)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .fontColor(this.textColor)
        .margin(20)
        .onClick(() => {
          this.num += 5;
        })
    }
    .width('100%')
  }
}

        6、自定义组件监听页面生命周期

// Index.ets
import { uiObserver, router, UIObserver } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  listener: (info: uiObserver.RouterPageInfo) => void = (info: uiObserver.RouterPageInfo) => {
    let routerInfo: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo();
    if (info.pageId == routerInfo?.pageId) {
      if (info.state == uiObserver.RouterPageState.ON_PAGE_SHOW) {
        console.log(`Index onPageShow`);
      } else if (info.state == uiObserver.RouterPageState.ON_PAGE_HIDE) {
        console.log(`Index onPageHide`);
      }
    }
  }
  aboutToAppear(): void {
    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
    uiObserver.on('routerPageUpdate', this.listener);
  }
  aboutToDisappear(): void {
    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
    uiObserver.off('routerPageUpdate', this.listener);
  }
  build() {
    Column() {
      Text(`this page is ${this.queryRouterPageInfo()?.pageId}`)
        .fontSize(25)
      Button("push self")
        .onClick(() => {
          router.pushUrl({
            url: 'pages/Index'
          })
        })
      Column() {
        SubComponent()
      }
    }
  }
}
@Component
struct SubComponent {
  listener: (info: uiObserver.RouterPageInfo) => void = (info: uiObserver.RouterPageInfo) => {
    let routerInfo: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo();
    if (info.pageId == routerInfo?.pageId) {
      if (info.state == uiObserver.RouterPageState.ON_PAGE_SHOW) {
        console.log(`SubComponent onPageShow`);
      } else if (info.state == uiObserver.RouterPageState.ON_PAGE_HIDE) {
        console.log(`SubComponent onPageHide`);
      }
    }
  }
  aboutToAppear(): void {
    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
    uiObserver.on('routerPageUpdate', this.listener);
  }
  aboutToDisappear(): void {
    let uiObserver: UIObserver = this.getUIContext().getUIObserver();
    uiObserver.off('routerPageUpdate', this.listener);
  }
  build() {
    Column() {
      Text(`SubComponent`)
    }
  }
}

五、if...else...条件渲染

        1、使用规则

  • 支持if、else和else if语句。

  • if、else if后跟随的条件语句可以使用状态变量或者常规变量(状态变量:值的改变可以实时渲染UI,常规变量:值的改变不会实时渲染UI)。

  • 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。

  • 条件渲染语句在涉及到组件的父子关系时是“透明”的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则。

  • 每个分支内部的构建函数必须遵循构建函数的规则,并创建一个或多个组件。无法创建组件的空构建函数会产生语法错误。

  • 某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制将同样应用于条件渲染语句内创建的组件。

        2、更新机制

        当if、else if后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:

  1. 评估if和else if的状态判断条件,如果分支没有变化,无需执行以下步骤。如果分支有变化,则执行2、3步骤:

  2. 删除此前构建的所有子组件。

  3. 执行新分支的构造函数,将获取到的组件添加到if父容器中。如果缺少适用的else分支,则不构建任何内容。

        条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。

@Entry
@Component
struct ViewA {
  @State count: number = 0;

  build() {
    Column() {
      Text(`count=${this.count}`)

      if (this.count > 0) {
        Text(`count is positive`)
          .fontColor(Color.Green)
      }

      Button('increase count')
        .onClick(() => {
          this.count++;
        })

      Button('decrease count')
        .onClick(() => {
          this.count--;
        })
    }
  }
}

 六、循环渲染

        在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

        ForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item: Object, index: number) => { return index + '__' + JSON.stringify(item); }。

        ArkUI框架对于ForEach的键值生成有一套特定的判断规则,这主要与itemGenerator函数的第二个参数index以及keyGenerator函数的第二个参数index有关,具体的键值生成规则判断逻辑如下图所示。

        1、创建规则 

        在确定键值生成规则后,ForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。

        组件的创建包括两种情况:

        a、 ForEach首次渲染(在ForEach首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件);

        b、ForEach非首次渲染(在ForEach组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件)。

        2、使用场景 

        ForEach组件在开发过程中的主要应用场景包括:数据源不变(在数据源保持不变的场景中,数据源可以直接采用基本数据类型)、数据源数组项发生变化(在数据源数组项发生变化的场景下,例如进行数组插入、删除操作或者数组项索引位置发生交换时,数据源应为对象数组类型,并使用对象的唯一ID作为最终键值)、数据源数组项子属性发生变化(当数据源的数组项为对象数据类型,并且只修改某个数组项的属性值时,由于数据源为复杂数据类型,ArkUI框架无法监听到@State装饰器修饰的数据源数组项的属性变化,从而无法触发ForEach的重新渲染。为实现ForEach重新渲染,需要结合@Observed和@ObjectLink装饰器使用)。

        3、使用建议        

          a、尽量避免在最终的键值生成规则中包含数据项索引index,以防止出现渲染结果非预期和渲染性能降低。如果业务确实需要使用index,例如列表需要通过index进行条件渲染,开发者需要接受ForEach在改变数据源后重新创建组件所带来的性能损耗;

        b、为满足键值的唯一性,对于对象数据类型,建议使用对象数据中的唯一id作为键值;

        c、基本数据类型的数据项没有唯一ID属性。如果使用基本数据类型本身作为键值,必须确保数组项无重复。因此,对于数据源会发生变化的场景,建议将基本数据类型数组转化为具备唯一ID属性的对象数据类型数组,再使用ID属性作为键值生成规则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1988453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一次性讲清AI外呼系统,再也不用人工打电话

相信大家都有了解现在接到的机器人电话越来越多,那么真正操作机器人代替人工打电话其实很简单,学会了自然是节省大量人工拨打电话的时间 为什么电销要用外呼系统|||在现代科技的迅猛发展中,AI机器人已逐渐在各行各业崭露头角,与传…

022_java.lang.ThreadLocal

ThreadLocal使用案例 在并发编程中有时候需要让线程互相协作,而协作可以使用共享数据的方式来实现。针对共享数据的操作就需要锁机制来控制并发行为。锁虽好,但是毕竟会在一定程度上让线程之间互相阻塞。前辈们认为在线程需要互相协作的前提下&#xff…

服务器测试之RAID知识梳理

最近开始整理RAID卡相关规格信息,所以再重新汇总整理一下RAID相关的知识点及细节,尽量写的详细简单使用图示让大家更好理解 1.什么是Raid? RAID 是英文 Redundant Array of Independent Disks 的缩写,中文简称为独立磁盘冗余阵列…

Nuxt3所有页面使用服务端渲染需要注意些什么?

其实服务端渲染很多时候并不是所有页面都需要使用的,但是如果有些项目真的需要所有页面都使用服务端渲染,此时服务器压力很大,那要如何处理更好呢? 一、是否所有页面都需要使用服务端渲染呢? 大家可参考以下这篇文…

【深度学习】基于YOLOV5模型的图像识别-目标检测的性能指标详解与计算方法

目标检测是计算机视觉中的重要任务,主要目的是在图像中识别并定位特定的物体。YOLO(You Only Look Once)系列模型作为目标检测领域的代表性方法之一,凭借其高效和准确的特点,广泛应用于实际场景中。本文通过详细介绍目…

三十一、【人工智能】【机器学习】- 自编码器 (Autoencoders)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

趣测系统源码获取,搭建系统详细教程,流量主+佣金+图文+挂载

一、趣测系统是什么? 趣测系统是一款集合了多种趣味测试的应用软件或小程序,以其独特的玩法和广泛的测试种类,为用户提供了全新的娱乐体验。该系统涵盖了心理测试、星座测试、性格测试、能力测试(如IQ、EQ)、情感测试…

数据结构(5.5_1)——哈夫曼树

带权路径长度: 结点的权 有某种现实含义的数值(如表示结点的重要性等) 结点的带权路径长度 从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积 树的带权路径长度 树中所有的叶结点的带权路径长度之和(WPL,Weighted Path Length) 哈夫曼树的定义&…

PyTorch深度学习实践——卷积神经网络

卷积神经网络 说明 卷积神经网络就是特征提取器,前一部分叫Feature Extraction,后一部分叫classification。卷积神经网络的过程是:卷积(线性变换,提取出重要的特征)、激活函数(非线性变换&…

【C++】:智能指针 -- RAII思想shared_ptr剖析

目录 一,内存泄漏二,智能指针的使用及原理2.1 RAII思想2.2 auto_ptr2.3 unique_ptr 三,shared_ptr(重点)3.1 shared_ptr的原理及使用3.2 shared_ptr的模拟实现1. 基本框架2. 引用计数的设计3. 拷贝构造4. 析构函数5. 赋值拷贝 3.3 shared_ptr…

Vue 3+Vite+Eectron从入门到实战系列之(三)一Electron热身运动(一)

前面我们已经把基础环境配置好了,在开始我们编写第一个页面之前,先尝试几个小的实验,体验下 electron 的乐趣。 更改我们应用的名称 系统默认的名字是从 package.json 中读取的,我们可以在这里更改。 {"name": "electron-vue3" }更改后,我们重新启动…

解决pycharm日志总是弹出“无法运行Git,未安装Git”的问题

需求分析 我电脑中安装了git,但是打开pycharm,右下角总是弹出 无法运行Git,未安装Git的日志。 解决方法 首先打开pycharm,按照以下路径,依次点击。 file -----settings-----version control -----Git----Git path(选择自己下载…

【Matplotlib】在 ax(Axes 对象)上使用 seaborn(简称 sns)绘图

在 ax(Axes 对象)上使用 seaborn(简称 sns)绘图时,你可以通过将 ax 作为参数传递给 seaborn 的绘图函数。这允许你将 seaborn 的图形绘制在指定的 ax 对象上,从而将多个图形组合在一个图形布局中。 示例代…

超高速直线模组究竟有多快?飞创直线模组最快速度是多少?

超高速直线模组的速度范围从每秒几毫米到每秒几十米,影响速度的因素包括电磁设计、冷却和机械结构等。超高速直线模组的速度也会因品牌、型号以及具体应用场景等因素而有所不同。 飞创直线模组的速度较快,最大速度可达10m/s,不同规格的直线模…

什么是护网?2024护网行动怎么参加?一文详解_护网具体是做啥的

前言 最近的全国护网可谓是正在火热的进行中,有很多网安小白以及准大一网安的同学在后台问我,到底什么是护网啊?怎么参加呢?有没有相关的学习资料呢?在下不才,连夜整理出来了这篇护网详解文章,希…

JavaWeb系列十一: Web 开发会话技术Cookie

会话技术-Cookie 基本介绍会话的两种技术cookie有什么用?cookie介绍二说cookiecookie可以用来干啥cookie常用方法cookie底层实现机制-创建和读取cookie应用实例-读取指定cookie和修改cookiecookie生命周期介绍应用实例 cookie有效路径有效路径规则应用实例作业布置cookie注意事…

日本求职面试时的注意事项、面试职场礼仪!

毋庸置疑的第一点就是—简历! 接到面试通知,就应该已经通过简历筛选的环节了。但也有些公司会要求面试时带上“履历书”和“职务经历书”。这时候也要好好查看简历上的日期、住址、电话等信息有没有误;以往职业经历有没有写清晰;…

批量修改文件名神器-文件名精灵

最近在网上发现一个批量修改文件名神器,这个软件叫“文件名精灵”,好用还免费。下载地址为

OJ-0807

题目 参考 import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);String input in.nextLine();String[] numStrs inp…