草庐IT

Eigen 欧拉角的说明,及四元数和旋转矩阵的变换

avenger_fang 2023-05-03 原文

        本文说明eulerAngles(0, 1, 2),和eulerAngles(2, 1, 0)的差异,并顺便将欧拉角、旋转矩阵、四元数一块的联系写了一下,也结合了一些有趣的博客内容。

1. 欧拉角旋转方向

不同的几何库对于旋转方向的正负号问题的定义不尽相同。这里主要验证下Eigen库旋转时,正负号判定的问题。如写简短测试程序:

Eigen::Matrix3d R;
    R = Eigen::AngleAxisd(M_PI / 4, Eigen::Vector3d::UnitX());
    Eigen::Vector3d input_point(0, 1, 0);
    Eigen::Vector3d input_point_x(1, 0, 0);
    Eigen::Vector3d output_point = R * input_point;
    Eigen::Vector3d output_point_x = R * input_point_x;

    std::cout << "output_point.x: " << output_point(0) << std::endl;
    std::cout << "output_point.y: " << output_point(1) << std::endl;
    std::cout << "output_point.z: " << output_point(2) << std::endl;
    std::cout << "output_point_x.x: " << output_point_x(0) << std::endl;
    std::cout << "output_point_x.y: " << output_point_x(1) << std::endl;
    std::cout << "output_point_x.z: " << output_point_x(2) << std::endl;

    if(output_point[2] > 0)
        std::cout << "逆时针为正" << std::endl;
    else
        std::cout << "顺时针为正" << std::endl;

output_point.x: 0
output_point.y: 0.707107
output_point.z: 0.707107
output_point_x.x: 1
output_point_x.y: 0
output_point_x.z: 0
逆时针为正

 绕X轴旋转,形成的矩阵是逆时针为正的轴角.

Eigen::Matrix3d R;
    R = Eigen::AngleAxisd(M_PI / 4, Eigen::Vector3d::UnitX());
    Eigen::Vector3d input_point(0, 1, 0);
    Eigen::Vector3d input_point_x(1, 0, 0);
    Eigen::Vector3d output_point = R * input_point;
    R = Eigen::AngleAxisd(M_PI / 4, Eigen::Vector3d::UnitZ());
    Eigen::Vector3d output_point_x = R * input_point_x;

    std::cout << "output_point.x: " << output_point(0) << std::endl;
    std::cout << "output_point.y: " << output_point(1) << std::endl;
    std::cout << "output_point.z: " << output_point(2) << std::endl;
    std::cout << "output_point_x.x: " << output_point_x(0) << std::endl;
    std::cout << "output_point_x.y: " << output_point_x(1) << std::endl;
    std::cout << "output_point_x.z: " << output_point_x(2) << std::endl;
    if(output_point[2] > 0)
        std::cout << "逆时针为正" << std::endl;
    else
        std::cout << "顺时针为正" << std::endl;

output_point.x: 0
output_point.y: 0.707107
output_point.z: 0.707107
output_point_x.x: 0.707107
output_point_x.y: 0.707107
output_point_x.z: 0
逆时针为正

2. eulerAngles函数参数说明

使用

Eigen::Matrix<float, 3, 1> last_eulerAngle = base_change_rotation.eulerAngles(2,1,0);
Eigen::Matrix<float, 3, 1> last_eulerAnglerpy = base_change_rotation.eulerAngles(0,1,2);
      printf("roll = %f, pitch = %f, yaw = %f\n",\
      last_eulerAngle[2] *180/M_PI , last_eulerAngle[1] *180/M_PI,last_eulerAngle[0]);
      printf("roll = %f, pitch = %f, yaw = %f\n",\
      last_eulerAngle[0] *180/M_PI , last_eulerAngle[1] *180/M_PI,last_eulerAngle[2]);

roll = -0.002344, pitch = -0.005306, yaw = 0.000028
roll = 0.001619, pitch = -0.005306, yaw = -0.000041

还有这样的:

roll = 180.000005, pitch = -180.000005, yaw =179.998781
roll = -0.000000, pitch = 0.000000, yaw =-0.001211

还能进行tf2的尝试:

//eulerAngles(2,1,0);

change roll = 179.973661, pitch = 179.993497, yaw = 179.982617

//eulerAngles(0,1,2);
rpy IMU change roll = 179.973661, pitch = 179.993497, yaw = 179.982617

//tf2 getEulerYPR(Rz, Ry, Rx)
rpy IMU change roll = -0.026333, pitch = 0.006509, yaw =-0.017388

####2

 change roll = -0.018427, pitch = 0.002789, yaw = 0.011282
rpy change roll = 179.981568, pitch = 179.997227, yaw = -179.988718
tf2 rpy change roll = -0.018427, pitch = 0.002789, yaw =0.011282

####3

change roll = 0.028579, pitch = -0.029884, yaw = 0.021761
rpy change roll = 0.028590, pitch = -0.029873, yaw = 0.021776
tf2 rpy change roll = 0.028579, pitch = -0.029884, yaw =0.021760

###

IMU change roll = -179.953592, pitch = -179.971388, yaw = 179.984152
rpy IMU change roll = 0.046389, pitch = -0.028626, yaw = -0.015842
tf2 rpy IMU change roll = 0.046397, pitch = -0.028613, yaw =-0.015865

#看下面,连续变化时eulerAngles(0,1,2)会出现接近180度时的正负号的变化,

eulerAngles(2,1,0)会出现 0.004586和179.979081变化

tf2的 tf2::Transform.getBasis().getEulerYPR(Rz, Ry, Rx)则更稳定

IMU change roll = 179.979062, pitch = 179.992545, yaw = 179.967832
rpy IMU change roll = 179.979081, pitch = 179.992525, yaw = 179.967832
tf2 rpy IMU change roll = -0.020938, pitch = 0.007450, yaw =-0.032174
lastest_NDT_time_ = 1662207100.606233, cloud_stamp = 1662207100.706121, time 99.887848
IMU change roll = -179.995420, pitch = -179.992389, yaw = 179.990194
rpy IMU change roll = 0.004586, pitch = -0.007603, yaw = -0.009804
tf2 rpy IMU change roll = 0.004588, pitch = -0.007602, yaw =-0.009807

可以看到,eulerAngles(0,1,2);和eulerAngles(2,1,0);都不太稳定,连续变化过程中,其获取的值会发生变化,选择使用tf2的欧拉角转换更佳。

 测试一下

double x = M_PI / 6;
    double y = M_PI / 4;
    double z = M_PI / 3;

    Eigen::Matrix3d R;
    R = Eigen::AngleAxisd(x, Eigen::Vector3d::UnitX()) *
        Eigen::AngleAxisd(y, Eigen::Vector3d::UnitY()) *
        Eigen::AngleAxisd(z, Eigen::Vector3d::UnitZ());

    auto angle = R.eulerAngles(0, 1, 2) * 180 / M_PI;
    auto angleypr = R.eulerAngles(2, 1, 0) * 180 / M_PI;
    std::cout << "X  = " << angle(0) << std::endl;
    std::cout << "Y  = " << angle(1) << std::endl;
    std::cout << "Z  = " << angle(2) << std::endl;

    std::cout << "yaw  = " << angleypr(0) << std::endl;
    std::cout << "pitch  = " << angleypr(1) << std::endl;
    std::cout << "roll  = " << angleypr(2) << std::endl;
    if ((std::abs(angle(0) - 30) < 0.001) &&
        (std::abs(angle(1) - 45) < 0.001) &&
        (std::abs(angle(2) - 60) < 0.001))
    {
        std::cout << "xyz" << std::endl;
    }

输出结果:

X  = 30
Y  = 45
Z  = 60
yaw  = 69.1188
pitch  = -7.28625
roll  = 51.8766
xyz

可以看到,一个旋转矩阵R通过eulerAngles(0, 1, 2),和eulerAngles(2, 1, 0)是不一样的;

    double x = M_PI / 6;
    double y = M_PI / 4;
    double z = M_PI / 3;

    Eigen::Matrix3d R;
    R = Eigen::AngleAxisd(x, Eigen::Vector3d::UnitX()) *
        Eigen::AngleAxisd(y, Eigen::Vector3d::UnitY()) *
        Eigen::AngleAxisd(z, Eigen::Vector3d::UnitZ());

    auto angle = R.eulerAngles(0, 1, 2) * 180 / M_PI;
    auto angleypr = R.eulerAngles(2, 1, 0) * 180 / M_PI;
    std::cout << "X  = " << angle(0) << std::endl;
    std::cout << "Y  = " << angle(1) << std::endl;
    std::cout << "Z  = " << angle(2) << std::endl;

    std::cout << "yaw  = " << angleypr(0) << std::endl;
    std::cout << "pitch  = " << angleypr(1) << std::endl;
    std::cout << "roll  = " << angleypr(2) << std::endl;
    if ((std::abs(angle(0) - 30) < 0.001) &&
        (std::abs(angle(1) - 45) < 0.001) &&
        (std::abs(angle(2) - 60) < 0.001))
    {
        std::cout << "xyz" << std::endl;
    }
    std::cout << "R = " << R <<std::endl;

    const double precision = 1e-5;
    double yaw  = 69.1188 * M_PI/180;
    double pitch  = -7.28625 * M_PI/180;
    double roll  = 51.8766 * M_PI/180;
    Eigen::Matrix3d new_R;
    new_R = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) *
            Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()) *
            Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX());
    std::cout << "new_R = " << new_R <<std::endl;

    auto new_angle = new_R.eulerAngles(0, 1, 2) * 180 / M_PI;
    auto new_angle_rpy = new_R.eulerAngles(2, 1, 0) * 180 / M_PI;
    bool re = R.isApprox(new_R, precision);
    std::cout << "new_X  = " << new_angle(0) << std::endl;
    std::cout << "new_Y  = " << new_angle(1) << std::endl;
    std::cout << "new_Z  = " << new_angle(2) << std::endl;

    std::cout << "new_yaw  = " << new_angle_rpy(0) << std::endl;
    std::cout << "new_pitch  = " << new_angle_rpy(1) << std::endl;
    std::cout << "new_roll  = " << new_angle_rpy(2) << std::endl;
    std::cout << "isApprox  = " << re << std::endl;

输出结果:

X  = 30
Y  = 45
Z  = 60
yaw  = 69.1188
pitch  = -7.28625
roll  = 51.8766
xyz
R =  0.353553 -0.612372  0.707107
 0.926777  0.126826 -0.353553
 0.126826   0.78033  0.612372
new_R =  0.353553 -0.612372  0.707107
 0.926777  0.126826 -0.353553
 0.126827   0.78033  0.612372
new_X  = 30
new_Y  = 45
new_Z  = 60
new_yaw  = 69.1188
new_pitch  = -7.28625
new_roll  = 51.8766
isApprox  = 1

这里你会好奇,为什么pitch角也是不一样的?

因为欧拉角处理顺序表示不一样,其意义也不一样.

总结:

第一种:

R = rx* ry * rz;

        R.eulerAngles(0, 1, 2) 的存储方式也是按照 [rx, ry,rz]存放的

        这种坐标变换描述是,先绕着自身坐标系X轴旋转rx,再绕着自身Y轴旋转ry, 再绕着自身Z轴旋转rz,可以认为是X-Y-Z欧拉角。

R = yaw * pitch * roll;右乘的方式实现的

        R.eulerAngles(2, 1, 0) 的存储方式也是按照 [yaw, pitch, roll]存放的.

        这种坐标变换描述是,先绕着自身坐标系Z轴旋转yaw,再绕着自身Y轴旋转pitch, 再绕着自身X轴旋转roll,可以认为是Z-Y-X欧拉角。

欧拉角和RPY角

        第一种是绕固定(参考)坐标轴旋转:假设开始两个坐标系重合,先将B绕A的X轴旋转γ角,再绕A的Y轴旋转β角,最后绕A的Z轴旋转α角,完成旋转。整个过程,A不动,B动。可以称其为X-Y-Z fixed angles或RPY角(Roll, Pitch, Yaw)。

由于是绕固定坐标系旋转,则旋转矩阵为:

R = Rz * Ry *Rx,乘法顺序:从右向左,左乘,先转的轴放在右边,后转的轴矩阵放在左边。

         另一种姿态描述方式是绕自身坐标轴旋转:假设开始两个坐标系重合,先将{B}绕自身的Z轴旋转α,然后绕旋转后的Y轴旋转β,最后绕旋转后的X轴旋转γ,就能旋转到当前姿态。

由于是绕动坐标系旋转,则旋转矩阵为:

 R = Rz * Ry *Rx,即绕动轴坐标系旋转是右乘,先转的轴放在左边,后转的轴是放在右边

        可以发现这两种描述方式得到的旋转矩阵是一样的,即绕固定坐标轴X-Y-Z旋转(γ,β,α)和绕自身动坐标轴Z-Y-X旋转(α,β,γ)的最终结果一样,只是描述的方法有差别而已。

单位四元数与旋转矩阵:

旋转轴的单位方向向量为K,则有:

 四元数转换为旋转矩阵:

 对应的四元数为:

 

 

这样求解的角度就在[-PI,PI] .

注意欧拉角有24种,分成绕动轴和绕固定轴。

第一种是按照旋转的轴的顺序,绕动轴的表示一共12种。

三个轴只用两个的:Proper Euler angles (z−x−z, x−y−x, y−z−y, z−y−z, x−z−x, y−x−y)
三个轴全都用的:Tait-Bryan angles (x−y−z, y−z−x, z−x−y, x−z−y, z−y−x, y−x−z)

而上面推导的公式是按照Z-Y-X顺序进行的。

 Axis-Angle与四元数的代码实现

        绕坐标轴的多次旋转可以等效为绕某一转轴旋转一定的角度。

初始化旋转向量:旋转角为alpha,旋转轴为(x,y,z),可以看到前面绕标准轴的旋转就是轴角+对应方向单位向量。
Eigen::AngleAxisd rotation_vector(alpha,Vector3d(x,y,z))
旋转向量转旋转矩阵
Eigen::Matrix3d rotation_matrix;
rotation_matrix=rotation_vector.matrix();

Eigen::Matrix3d rotation_matrix;
rotation_matrix=rotation_vector.toRotationMatrix();
旋转向量转欧拉角(Z-Y-X,即RPY)
Eigen::Vector3d eulerAngle=rotation_vector.matrix().eulerAngles(2,1,0);
旋转向量转四元数,通过拷贝构造和赋值构造函数
Eigen::Quaterniond quaternion(rotation_vector);

Eigen::Quaterniond quaternion;quaternion=rotation_vector;
欧拉角转旋转矩阵
Eigen::AngleAxisd rollAngle(AngleAxisd(eulerAngle(2),Vector3d::UnitX()));
Eigen::AngleAxisd pitchAngle(AngleAxisd(eulerAngle(1),Vector3d::UnitY()));
Eigen::AngleAxisd yawAngle(AngleAxisd(eulerAngle(0),Vector3d::UnitZ())); 
Eigen::Matrix3d rotation_matrix=yawAngle*pitchAngle*rollAngle;

其他从旋转矩阵转欧拉角的程序:

#include <tf/tf.h>
double roll, pitch, yaw;//定义存储r\p\y的容器
tf::Matrix3x3(quat).getRPY(roll, pitch, yaw);//进行转换


tf::Quaternion q;
q.setRPY(roll, pitch, yaw);
//create ros msg
tf::Quaternion createQuaternionFromRPY(double roll,double pitch,double yaw);


static Eigen::Matrix<typename Derived::Scalar, 3, 3> ypr2R(const Eigen::MatrixBase<Derived> &ypr)
    {
        typedef typename Derived::Scalar Scalar_t;

        Scalar_t y = ypr(0) / 180.0 * M_PI;
        Scalar_t p = ypr(1) / 180.0 * M_PI;
        Scalar_t r = ypr(2) / 180.0 * M_PI;

        Eigen::Matrix<Scalar_t, 3, 3> Rz;
        Rz << cos(y), -sin(y), 0,
            sin(y), cos(y), 0,
            0, 0, 1;

        Eigen::Matrix<Scalar_t, 3, 3> Ry;
        Ry << cos(p), 0., sin(p),
            0., 1., 0.,
            -sin(p), 0., cos(p);

        Eigen::Matrix<Scalar_t, 3, 3> Rx;
        Rx << 1., 0., 0.,
            0., cos(r), -sin(r),
            0., sin(r), cos(r);

        return Rz * Ry * Rx;
    }

旋转矩阵->欧拉角 

static Eigen::Vector3d R2ypr(const Eigen::Matrix3d &R)
    {
        Eigen::Vector3d n = R.col(0);
        Eigen::Vector3d o = R.col(1);
        Eigen::Vector3d a = R.col(2);

        Eigen::Vector3d ypr(3);
        double y = atan2(n(1), n(0));
        double p = atan2(-n(2), n(0) * cos(y) + n(1) * sin(y));
        double r = atan2(a(0) * sin(y) - a(1) * cos(y), -o(0) * sin(y) + o(1) * cos(y));
        ypr(0) = y;
        ypr(1) = p;
        ypr(2) = r;

        return ypr / M_PI * 180.0;
    }

旋转矩阵->四元数

Eigen::Quaterniond q = Eigen::Quaterniond(R);  
    q.normalize(); 

        经典力学中使用zxz,量子力学使用的是zyz,航空航天使用zyx/zxy。所以在跨行业或者跨模块协作的时候,一定要问清楚对方是哪一种欧拉角。

        不同的转序和不同的轴对应的万向节死锁的位置是不一样的,因此每个专业都想把万向节死锁的位置安排在自己最不常用的位置。但是,无论哪一种欧拉角都是避免不了万向节死锁的。

        比如航空领域中,滚转俯仰偏航角有明确的物理意义。如果对导航的定义是是北(x)东(y)地(z),那这种情况下,飞机本身的坐标系定义就必须是:前(x)右(y)下(z),转序就是zyx(321)。如果对导航的定义是是东(x)北(y)天(z), 那这种情况下,飞机本身的坐标系定义就必须是:右(x)前(y)上(z).转序就是zxy(312)。

欧拉角的优缺点:

优点:

1 简单,三个数就能表示出来

2 直观,用手就能比划出姿态

缺点:

1 万向节死锁

2 没办法进行旋转的叠加,必须借助旋转矩阵。这就是很少看见用欧拉角相加减原因。

3 插值误差大,因为是三个轴进行的旋转。但是四元数就十分适合插值。

4 欧拉角的种类太多,不同专业背景之间的沟通容易出问题。

        综上,欧拉角在运动变换的时候很少用来直接参与计算,通常采用旋转矩阵(通过李群)或者四元数来进行表示。近年来,四元数的使用非常简便,广泛用于SLAM等领域,近年来的李群和李代数的应用作为类似于四元数的刚体运动操作方法让旋转的扰动更便于计算与应用。接下来会对李群和李代数进行部分说明。欧拉角的计算不好使,通常用于显示

有关Eigen 欧拉角的说明,及四元数和旋转矩阵的变换的更多相关文章

  1. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  2. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  3. 欧拉角表示的姿态矩阵(313和312转序) - 2

    一、习惯约定图片来自PSINS(高精度捷联惯导算法)PSINS工具箱入门与详解.pptx二、基本旋转矩阵绕x轴逆时钟旋转α\alphaα角度Rx(α)=[ 1000cos⁡αsin⁡α0−sin⁡αcos⁡α]R_x(\alpha)=\begin{bmatrix}\1&0&0\\0&\cos\alpha&\sin\alpha\\0&-\sin\alpha&\cos\alpha\end{bmatrix}Rx​(α)=​ 100​0cosα−sinα​0sinαcosα​​绕y轴逆时钟旋转α\alphaα角度Ry(α)=[ cos⁡α0−sin⁡α010sin⁡α0cos⁡α]R_y(\alpha

  4. 欧拉角、旋转矩阵及四元数 - 2

    欧拉角、旋转矩阵及四元数1.简介2.欧拉角2.1欧拉角定义2.2右手系和左手系2.3转换流程3.旋转矩阵4.四元数4.1四元数与欧拉角和旋转矩阵之间等效变换4.2测试Matlab代码5.总结1.简介常用姿态参数表达方式包括方向余弦矩阵、欧拉轴/角参数、欧拉角、四元数以及罗德里格参数等。高分辨率光学遥感卫星主要采用欧拉角与四元数对姿态参数进行描述。这里着重讲解欧拉角、旋转矩阵和四元数。2.欧拉角2.1欧拉角定义欧拉角是表征刚体旋转的一种方法之一,由莱昂哈德·欧拉引入的三个角度,用于描述刚体相对于固定坐标系的方向。在摄影测量、空间科学或其它技术领域,一般用一组(三个)欧拉角描述两个空间坐标之间的旋

  5. ruby - 我可以在传递给方法的 block 上强制执行元数吗? - 2

    有什么方法可以“开启”使用Proc.new或Kernel.proc实例化的Proc的严格元数强制执行,使其表现得像Proc用lambda实例化?我的initialize方法采用block&action并将其分配给实例变量。我希望action严格执行arity,因此当我稍后对其应用参数时,它会引发一个ArgumentError,我可以挽救它并引发一个更有意义的异常。基本上:classCommandattr_reader:name,:actiondefinitialize(name,&action)@name=name@action=actionenddefperform(*args)be

  6. 交叉编译eigen 到hi3559 - 2

    3559操作自记录0502ubuntu操作日志sudoapt-getinstallcmake-qt-guiwhereisaarch64-himix100-linux-gccaarch64-himix100-linux-gcc:/opt/hisi-linux/x86-arm/aarch64-himix100-linux/bin/aarch64-himix100-linux-gcc然后把同级的gnu放进来了,然后confige,然后generate然后make(没有输出安全通过),然后makeinstallhaitu@ubuntu:~/eigen-3.4.0/aarch_eigen$cdbuild

  7. 欧拉系统安装与部署NextCloud及数据迁移 - 2

    欧拉系统部署NextCloud与常见部署问题解决以及数据盘迁移一、欧拉系统安装二、openEuler安装图形界面Ukui三、yum安装的npm包进行本地保存设置(个人任务需要)四、部署nextCloud4.1构建LAMP环境基础4.1.1开启httpd,防火墙端口号4.1.2开启MariaDB服务4.1.3安装并测试php4.2下载安装nextCloud4.2.1创建nextCloud数据库,存放网盘文件索引与用户信息4.2.2拷贝NextCloud并创建data目录,目录赋予权限五、离线npm包方式部署NextCloud(个人需要,正常联网状态搭建LAMP环境后,拷贝NextCloud安装即

  8. ruby - 欧拉计划 1 :Find the sum of all the multiples of 3 or 5 below 1000 - 2

    我正在尝试使用ProjectEuler中的Ruby解决数学问题。Here是我尝试的第一个:Ifwelistallthenaturalnumbersbelow10thataremultiplesof3or5,weget3,5,6and9.Thesumofthesemultiplesis23.Findthesumofallthemultiplesof3or5below1000.请帮助我改进我的代码。total=0(0...1000).eachdo|i|total+=iif(i%3==0||i%5==0)endputstotal 最佳答案

  9. ruby - 如何获取 "super"的元数? - 2

    假设您正在用不同的元数覆盖子类中的方法:classAdeffoo(arg)#arityis1#doingsomethinghereendendclassB有没有办法在线获取super的元数?(实际用例:我调用super时知道父类(superclass)不接受任何参数。但是,如果父类(superclass)实现(在gem中)发生变化,我想发出警告。)感谢您的帮助! 最佳答案 关于您的实际用例:无需亲自检查参数。打电话super(arg1)如果参数计数不匹配,Ruby将引发ArgumentError。更新由于一些反对票,我想我应该回答你

  10. 华为OD机试 -旋转骰子(Python) | 机试题算法思路 【2023】 - 2

    最近更新的博客华为OD机试-卡片组成的最大数字(Python)|机试题算法思路华为OD机试-网上商城优惠活动(一)(Python)|机试题算法思路华为OD机试-统计匹配的二元组个数(Python)|机试题算法思路华为OD机试-找到它(Python)|机试题算法思路华为OD机试-九宫格按键输入(Python)|机试算法备考思路华为OD机试-身高排序(Python)|备考思路使用说明参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。华为OD清单查看地址:blog.csdn.net/hihell/catego

随机推荐