`
hqs7636
  • 浏览: 215715 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

函 数 2.014

阅读更多
[size=large]函数体:
块语句
语句体
In语句 语句体
Out语句 语句体
In语句 Out语句 语句体
Out语句 In语句 语句体

In语句:
in 语句块

Out语句:
out 语句块
out ( 标识符 ) 语句块

语句块:
body 语句块

  2.014

Pure Functions

Pure functions are functions that produce the same result for the same arguments. To that end, a pure function: 

has parameters that are all invariant or are implicitly convertible to invariant 
does not read or write any global mutable state 

A pure function can throw exceptions and allocate memory via a NewExpression. 

int x;
invariant int y;
const int* pz;

pure int foo(int i,     // ok, implicitly convertible to invariant
             char* p,         // error, not invariant
             const char* q,   // error, not invariant
             invariant int* s // ok, invariant
            )
{
    x = i;    // error, modifying global state
    i = x;    // error, reading mutable global state
    i = y;    // ok, reading invariant global state
    i = *pz;  // error, reading const global state
    return i;
}


Nothrow Functions

Nothrow functions do not throw any exceptions derived from class Exception. 



1 虚函数(Virtual Functions)

虚函数指的是这样一类函数:它们通过叫作 vtbl[] 的 函数指针表 被间接调用,而非直接进行调用。所有的非静态、非私有、非模板 成员函数都是虚函数。这听起来也许有些低效,但是,因为 D 编译器在生成代码时知道所有的类层次结构,所以,所有未被重写的函数可以被优化成非虚函数。

事实上,C++ 程序员倾向于“在不确定时,声明它为虚函数”;

而 D 采用的方式是“都声明成虚函数,除非我们可以证明它可以是非虚函数”,这样综合后的结果就是产生更多更直接的函数调用。这也可以大大减少由于没有将会被重写(voerride)的函数声明为虚函数,而引起的错漏。

因为带有“非 D 连接特性(non-D linkage)”的函数不能是虚函数,因此不能被重写。

因为成员模板函数不能是虚的,因此不能被重写。

标记为 final 的函数不可以在派生类中被重写,除非它们同时也是 private 类型。

例如:
class A
{
int def() { ... }
final int foo() { ... }
final private int bar() { ... }
private int abc() { ... }
}

class B : A
{
int def() { ...} // 正确,重写 A.def
int foo() { ...} // 错误,A.foo 是 final 的
int bar() { ...} // 正确,A.bar 是 final private 的,但不是 virtual 的
int abc() { ...} // 正确,A.abc 不是 virtual 的,B.abc 是 virtual 的
}

void test(A a)
{
a.def(); // 调用 B.def
a.foo(); // 调用 A.foo
a.bar(); // 调用 A.bar
a.abc(); // 调用 A.abc
}

void func()
{ B b = new B();
test(b);
}

协变返回类型(covariant return types)”,即表示在 派生类 里的重写函数可以返回这样一种类型——此类型派生自 被重写函数 所返回的类型:

class A { }

class B : A { }

class Foo
{
A test() { return null; }
}

class Bar : Foo
{
B test() { return null; } // 重写,并且同 Foo.test() 是协变的
}

2.014
Virtual functions all have a hidden parameter called the this reference, which refers to the class object for which the function is called.



2 函数继承(inheritance)和重写(overidding)

派生类中的函数将重载 基类中 同函数名、同参数类型 的函数:

class A
{
int foo(int x) { ... }
}

class B : A
{
override int foo(int x) { ... }
}
void test()
{
B b = new B();
bar(b);
}
void bar(A a)
{
a.foo(1); // 调用 B.foo(int)
          //2.014  issues runtime error (instead of calling A.foo(int))
}

而且,在进行重载解析的时候,基类中对应的那些函数都不会被考虑的:

class A
{
int foo(int x) { ... }
int foo(long y) { ... }
}

class B : A
{
override int foo(long x) { ... }
}

void test()
{
B b = new B();
b.foo(1); // 调用 B.foo(long),因为不会考虑 A.foo(int)
A a = b;
a.foo(1); // calls A.foo(int)
}

要在重载解析过程中让基类的那些函数有效,请使用“别名声明”:

class A
{
int foo(int x) { ... }
int foo(long y) { ... }
}

class B : A
{
alias A.foo foo;
override int foo(long x) { ... }
}

void test()
{
B b = new B();
bar(b);
}
void bar(A a)
{
a.foo(1); // 调用 A.foo(int)
B b = new B();
b.foo(1); // 调用 A.foo(int)
}


 2.014
If such an AliasDeclaration is not used, the derived class's functions completely override all the functions of the same name in the base class, even if the types of the parameters in the base class functions are different. If, through implicit conversions to the base class, those other functions do get called, an std.HiddenFuncError exception is raised: 

import std.hiddenfunc;

class A
{
     void set(long i) { }
     void set(int i)  { }
}
class B : A
{
     void set(long i) { }
}

void foo(A a)
{   int i;
    try
    {
        a.set(3);   // error, throws runtime exception since
                    // A.set(int) should not be available from B
    }
    catch (HiddenFuncError o)
    {
	i = 1;
    }
    assert(i == 1);
}

void main()
{
    foo(new B);
}

If an HiddenFuncError exception is thrown in your program, the use of overloads and overrides needs to be reexamined in the relevant classes.



函数参数的默认值不会被继承的:
class A
{
void foo(int x = 5) { ... }
}

class B : A
{
void foo(int x = 7) { ... }
}

class C : B
{
void foo(int x) { ... }
}

void test()
{
A a = new A();
a.foo(); // 调用 A.foo(5)
B b = new B();
b.foo(); // 调用 B.foo(7)
C c = new C();
c.foo(); // 错误,C.foo 需要一个参数
}


3 内联函数(Inline Functions)

D 中没有 inline 关键字。编译器决定是否将一个函数内联,就像 register 关键字不再同编译器是否将变量存在 寄存器中 相关一样。(也没有 register 关键字。)


4 函数重载(Function Overloading)

在 C++ 中,函数重载有很多复杂的级别,一些被定义为“更好的”匹配。如果代码编写者
利用函数重载选择时更为细微的行为,代码就会变得难以维护。不仅 C++ 专家很难弄明白
为什么选择这个函数而不选择哪个,不同的 C++ 编译器也可能会采用不同的方式实现这个
充满技巧的特征,这造成了微妙而灾难性的结果。

在 D 中,函数重载很简单。允许精确匹配,允许包含隐式转换的匹配,除此之外就不匹
配。

如果有多于一个匹配,就是错误。

非 D 链接的函数不允许重载。

上一节别改成如下的:2.014

Function Overloading

Functions are overloaded based on how well the arguments to a function can match up with the parameters. The function with the best match is selected. The levels of matching are: 

no match 
match with implicit conversions 
match with conversion to const 
exact match 

Each argument (including any this pointer) is compared against the function's corresponding parameter, to determine the match level for that argument. The match level for a function is the worst match level of each of its arguments.

If two or more functions have the same match level, then partial ordering is used to try to find the best match. Partial ordering finds the most specialized function. If neither function is more specialized than the other, then it is an ambiguity error. Partial ordering is determined for functions f() and g() by taking the parameter types of f(), constructing a list of arguments by taking the default values of those types, and attempting to match them against g(). If it succeeds, then g() is at least as specialized as f(). For example: 

class A { }
class B : A { }
class C : B { }
void foo(A);
void foo(B);

void test()
{
  C c;
  /* Both foo(A) and foo(B) match with implicit conversion rules.
   * Applying partial ordering rules,
   * foo(B) cannot be called with an A, and foo(A) can be called
   * with a B. Therefore, foo(B) is more specialized, and is selected.
   */
  foo(c); // calls foo(B)
}

A function with a variadic argument is considered less specialized than a function without. 

Functions defined with non-D linkage cannot be overloaded. because the name mangling does not take the parameter types into account. 

Overload Sets
Functions declared at the same scope overload against each other, and are called an Overload Set. A typical example of an overload set are functions defined at module level: 

module A;
void foo() { }
void foo(long i) { }
A.foo() and A.foo(long) form an overload set. A different module can also define functions with the same name: 

module B;
class C { }
void foo(C) { }
void foo(int i) { }
and A and B can be imported by a third module, C. Both overload sets, the A.foo overload set and the B.foo overload set, are found. An instance of foo is selected based on it matching in exactly one overload set: 

import A;
import B;

void bar(C c)
{
    foo();    // calls A.foo()
    foo(1L);  // calls A.foo(long)
    foo(c);   // calls B.foo(C)
    foo(1,2); // error, does not match any foo
    foo(1);   // error, matches A.foo(long) and B.foo(int)
    A.foo(1); // calls A.foo(long)
}

Even though B.foo(int) is a better match than A.foo(long) for foo(1), it is an error because the two matches are in different overload sets. 

Overload sets can be merged with an alias declaration:

import A;
import B;

alias A.foo foo;
alias B.foo foo;

void bar(C c)
{
    foo();    // calls A.foo()
    foo(1L);  // calls A.foo(long)
    foo(c);   // calls B.foo(C)
    foo(1,2); // error, does not match any foo
    foo(1);   // calls B.foo(int)
    A.foo(1); // calls A.foo(long)
}






4.1 函数形式参数(Function Parameters)

这些参数可以是 in、out、ref 或者 lazy。默认是 in;其它的参数工作起来跟存储类别
(storage class)一样。

例如:
int foo(int x, out int y, ref int z, int q);

x 为 in,y 为 out,z 为 ref,而 q 为 in。

out 已经很少见了,而 ref 则更少见,因此如果使用这些特性就需要使用关键字,而将 in
作为默认值。

上面这段被改成:2.014

Parameter storage classes are in, out, ref, lazy, final, const, invariant, or scope. 

For example: 
int foo(in int x, out int y, ref int z, int q);

x is in, y is out, z is ref, and q is none. 

The in storage class is equivalent to const scope. 

If no storage class is specified, the parameter becomes a mutable copy of its argument. 


• 函数声明清楚的表示了哪些是函数的输入,哪些是函数的输出。
• 不再需要单独使用一种叫 IDL 语言。
• 可以给编译器提供更多的信息,从而可以提供更好的错误检查并生成更好的代码。

out 参数被设为对应类型的默认值。

例如:
void foo(out int x)
{
// 在 foo() 的开始,x 被设置为 0
}
int a = 3;
foo(a);
// a 现在为 0

void abc(out int x)
{
x = 2;
}

int y = 3;
abc(y);
// y 现在为 2

void def(ref int x)
{
x += 1;
}

int z = 3;
def(z);
// z 现在为 4

对于通过引用传递的动态数组和对象参数,in/out/ref 只会作用到 该引用上, 而不会是那些内容里。

懒式参数被求值的时间不是以函数被调用时,而是参数在函数内被求值时进行的。因此,懒
式参数会被计算 0 次或多次。

懒式参数不能是一个左值。

void dotimes(int n, lazy void exp)
{
while (n--)
exp();
}

void test()
{ int x;
dotimes(3, writefln(x++));
}

控制台输出:
01
2

void 类型的懒式参数不能接受一个任何类型的参数。


5 参数可变型函数

那些带有可变数目参数的函数就叫做参数可变型(variadic)函数。

一个参数可变型函数可以有下面三种形式:

1. C-风格的参数可变型函数
2. 带有类型信息的参数可变型函数
3. 类型安全的参数可变型函数


5.1 C-风格的参数可变型函数

C-风格的参数可变型函数被声明时在所必需的函数参数里带有“...”参数。它有一个非D连
接属性,如 extern (C):

extern (C) int foo(int x, int y, ...);
foo(3, 4); // 正确
foo(3, 4, 6.8); // 正确,参数可变型函数
foo(2); // 错误,y 是一个必需的参数

必须至少声明一个固定型参数。

extern (C) int def(...); // 错误,必须至少有一个参数

C-风格的参数可变型函数符合 C 对于参数可变型函数的调用协定,而且对于调用像
printf 那样的 C 库函数最有用。这些参数可变型函数的实现会声明一个特殊的局部变
量:_argptr,此变量是一个指向可变参数里的第一个的 void* 型指针。

要访问这些参数,_argptr 就必须被转换成一所期望参数类型的指针:

foo(3, 4, 5); // 第一个可变型参数是 5
int foo(int x, int y, ...)
{ int z;
z = *cast(int*)_argptr; // z 被设置为 5
}

为了避开不同 CPU 结构上的各种奇特的堆栈分布带来的麻烦,请使用 std.c.stdarg 访问那些可变(variadic)参数:

import std.c.stdarg;


5.2 D-风格的参数可变型函数

带有参数和类型信息的参数可变型函数声明方式:在必需的函数参数之后带上参数“...”。

它有 D 连接属性,因此不需要声明任何非可变型参数:

int abc(char c, ...); // 一个必需的参数: c
int def(...); // 正确

这些参数可变型函数会声明一个特殊的局部变量:_argptr,此变量是一个指向第一个可变
参数的 void* 型指针。要访问这些参数,_argptr 就必须被转换成一所期望参数类型的指
针:

foo(3, 4, 5); // 第一个可变型参数是 5
int foo(int x, int y, ...)
{ int z;
z = *cast(int*)_argptr; // z 被设置为 5
}

一个名叫 _arguments 而类型为 TypeInfo[] 的额外的隐藏参数会被传递给该函
数。_arguments 会给出参数的数目以及每一个的类型,这样可以创建类型安全的 variadic 函数。

import std.stdio;

class Foo { int x = 3; }

class Bar { long y = 4; }

void printargs(int x, ...)
{
writefln("%d arguments", _arguments.length);
for (int i = 0; i < _arguments.length; i++)
{ _arguments[i].print();

if (_arguments[i] == typeid(int))
{
int j = *cast(int *)_argptr;
_argptr += int.sizeof;
writefln("\t%d", j);
}

else if (_arguments[i] == typeid(long))
{
long j = *cast(long *)_argptr;
_argptr += long.sizeof;
writefln("\t%d", j);
}

else if (_arguments[i] == typeid(double))
{
double d = *cast(double *)_argptr;
_argptr += double.sizeof;
writefln("\t%g", d);
}

else if (_arguments[i] == typeid(Foo))
{
Foo f = *cast(Foo*)_argptr;
_argptr += Foo.sizeof;
writefln("\t%X", f);
}

else if (_arguments[i] == typeid(Bar))
{
Bar b = *cast(Bar*)_argptr;
_argptr += Bar.sizeof;
writefln("\t%X", b);
}

else
assert(0);
}
}

void main()
{
Foo f = new Foo();
Bar b = new Bar();
writefln("%X", f);
printargs(1, 2, 3L, 4.5, f, b);
}

其输出为:

00870FE0
5 arguments
int
2
long
3
double
4.5
Foo
00870FE0
Bar
00870FD0

为了避开不同 CPU 结构上的各种奇特的堆栈分布带来的麻烦,请使用 std.stdarg 访问那些可变(variadic)参数:

import std.stdio;
import std.stdarg;

void foo(int x, ...)
{
writefln("%d arguments", _arguments.length);
for (int i = 0; i < _arguments.length; i++)
{ _arguments[i].print();

if (_arguments[i] == typeid(int))
{
int j = va_arg!(int)(_argptr);
writefln("\t%d", j);
}

else if (_arguments[i] == typeid(long))
{
long j = va_arg!(long)(_argptr);
writefln("\t%d", j);
}

else if (_arguments[i] == typeid(double))
{
double d = va_arg!(double)(_argptr);
writefln("\t%g", d);
}

else if (_arguments[i] == typeid(FOO))
{
FOO f = va_arg!(FOO)(_argptr);
writefln("\t%X", f);
}

else
assert(0);
}
}


5.3 类型安全的参数可变型函数

使用类型安全的参数可变型函数的情形是:参数的可变部分被用于创建一个数组或一个类对
象。

对于数组:
int test()
{
return sum(1, 2, 3) + sum(); // 返回 6+0
}

int func()
{
int[3] ii = [4, 5, 6];
return sum(ii); // 返回 15
}

int sum(int[] ar ...)
{
int s;
foreach (int x; ar)
s += x;
return s;
}

对于静态数组:
int test()
{
return sum(2, 3); // 错误,对于数组需要 3 个值
return sum(1, 2, 3); // 返回 6
}

int func()
{
int[3] ii = [4, 5, 6];
int[] jj = ii;
return sum(ii); // 返回 15
return sum(jj); // 错误,类型不匹配
}

int sum(int[3] ar ...)
{
int s;
foreach (int x; ar)
s += x;
return s;
}

对于类对象:
class Foo
{
int x;
char[] s;
this(int x, char[] s)
{
this.x = x;
this.s = s;
}
}

void test(int x, Foo f ...);
...
Foo g = new Foo(3, "abc");
test(1, g); // 正确,因为 g 是 Foo 的实例
test(1, 4, "def"); // 正确
test(1, 5); // 错误,不能匹配 Foo 的构造函数

实现可能在堆栈上构造对象或数组实例。因此,在参数可变型返回之后 引用该实例 就会出现
一个错误:
Foo test(Foo f ...)
{
return f; // 错误,在返回之后 f 实例内容无效
}

int[] test(int[] a ...)
{
return a; // 错误,在返回之后数组内容无效
return a[0..1]; // 错误,在返回之后数组内容无效
return a.dup; // 正确,因为做了复本
}

对于其它类型,参数会自己建立,就像下面的:
int test(int i ...)
{
return i;
}
...
test(3); // 返回 3
test(3, 4); // 错误,太多参数
int[] x;
test(x); // 错误,类型不匹配


5.4 懒式参数可变型函数

如果可变型参数是一个不带参数的委托数组:

void foo(int delegate()[] dgs ...);

那么跟该委托的类型不匹配的每一个参数会被转换成一个委托。

int delegate() dg;
foo(1, 3+x, dg, cast(int delegate())null);

同等于:
foo( { return 1; }, { return 3+x; }, dg, null );


6 局部变量

如果使用一个未被赋值过的局部变量,会被视为错误。编译器的实现未必总能够检测到这些
情况。其他语言的编译器有时会为此发出警告,但是因为这种情况几乎总是意味着存在错
漏,所以应该把它处理为错误。

如果声明一个变量但却从未使用,会被视为错误。死变量,如同过时的死代码一样,都会使
维护者迷惑。

如果声明的一个变量掩盖了统一函数中的另一个变量,会被视为错误:

void func(int x)
{ int x; 错误,掩盖了前面定义的 x
double y;
...
{ char y; 错误,掩盖了前面定义的 y
int z;
}
{ wchar z; 合法,上一个 z 超出了作用域
}
}

因为这种情况看起来不合理,在实践中出现这种情况时不是一个错漏至少看起来也像一个错
漏。

如果返回一个局部变量的地址或引用,会被视为错误。

如果局部变量同标签同名,会被视为错误。


[/size]

。。。。。。。。。。。
分享到:
评论

相关推荐

    Android开发BLE 串口调试工具,用来和底层进行一些握手协议的调试

    【Android】开发BLE 串口调试工具,用来和底层进行一些握手协议的调试。

    机械设计自动锁垫片机(sw18可编辑+工程图+BOM)非常好的设计图纸100%好用.zip

    机械设计自动锁垫片机(sw18可编辑+工程图+BOM)非常好的设计图纸100%好用.zip

    基于Mediapipe的手势识别前端应用可执行程序+说明.zip

    基于Mediapipe的手势识别前端应用可执行程序+说明.zip # 项目简介 * 基于AutoHotkey制作的摄像头手势识别软件。能让你的电脑摄像头在识别手势后,执行自定义的电脑操作命令。同时也集成了语音识别功能,可调用Windows自带API实现简单的语音助手功能。 * 手势识别调用了高性能的Mediapipe动态链接库来免部署实现。而电脑自动化操作使用AutoHotkey脚本语言来实现,它能更方便的对电脑进行深度调用和流程自动化处理。 # 使用介绍 * 测试环境:Win10 64位(专业版完整镜像) * **第一次运行 Visual_Gesture_Recognition.exe**时,会提示下载手势识别的**依赖包**。点击**确定**后,跟着提示**点击自动下载**

    node-v4.8.0.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    python烟花代码.zip

    python烟花代码python烟花代码.zip python烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zippython烟花代码.zip

    如何提高APP商业变现能力.docx

    如何提高APP商业变现能力.docx

    node-v12.19.1-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    数据分析:揭示数据背后的智慧与力量

    在数字化时代,数据已成为一种宝贵的资源,而数据分析则是解锁这一资源的关键。数据分析是指运用适当的统计分析和数据挖掘方法,对收集来的大量数据进行详细的研究和概括总结,以最大化地开发数据的功能,发挥数据的作用。 数据分析的过程涉及数据的收集、整理、转化、建模和解释等多个环节。通过对比分析法、分组分析法、结构分析法等多种方法,我们能够深入挖掘数据中的隐藏信息和内在规律,为企业决策、市场研究、科学研究等领域提供有力的支持。 数据分析在现代社会中的应用越来越广泛。例如,在市场调研中,通过对消费者需求、竞争品牌分布等数据的分析,企业可以了解市场潜力、竞争优势和定位策略,从而制定有效的市场推广策略。在社交媒体数据分析中,企业可以通过分析用户的关注人群、点赞、转发等行为,揭示用户的兴趣爱好、消费倾向和口碑传播效果,从而制定有针对性的营销策略。 数据分析工具和技术的发展也极大地推动了数据分析的普及和应用。如R语言和Python语言等编程工具,以及SAS等商业化的数据分析软件,都为数据分析提供了强大的支持。这些工具不仅具有丰富的统计函数和图表绘制能力,还具有高度的灵活性和可扩展性,可以满足各种要求

    水和废水处理化学品的选择和使用指南

    水和废水处理化学品的选择和使用指南

    python输出虚拟棋盘代码示例

    在Python中,可以使用多种方法来创建一个虚拟棋盘。下面是一个简单的示例,使用字符串和循环来创建一个8x8的国际象棋棋盘。 这段代码定义了一个函数print_chessboard,它首先定义了棋盘的一半,然后通过循环来构建整个棋盘。棋盘的每个格子用空格分隔,并且棋盘的行号用数字表示。棋盘的黑白格子使用字符串white和black来表示,其中white表示白格子,而black表示黑格子。 运行这段代码,你会在控制台看到一个8x8的棋盘,其中棋盘的行号从1到8,列号从A到H,棋盘的黑白格子交替出现。 请注意,这个棋盘是虚拟的,仅用于展示布局,并没有实现任何棋盘游戏的逻辑。如果你需要实现一个可以进行游戏的棋盘,你需要添加更多的代码来处理棋子的移动和游戏规则。

    基于modbus协议的大屏数据监控,使用modbus slave模拟数据,串口服务器获取温湿度

    系统使用了Modbus协议完成数据的获取工作,通过Mqtt协议与后端进行连接,获取了数据,完成了数据采集工作。后端通过对数据的处理,进行了数据存储,和接口api的处理。通过WebSocket协议来推送数据。前端展示请求的后端数据。通过此流程完成了工业暖通空调系统的开发。

    机械设计大倾角波状挡边带式输送机sw17可编辑非常好的设计图纸100%好用.zip

    机械设计大倾角波状挡边带式输送机sw17可编辑非常好的设计图纸100%好用.zip

    常见移动变现术语(mobile monetization).docx

    常见移动变现术语(mobile monetization).docx

    R语言绘制SCI科研小提琴图源代码.zip

    把input里面的数据替换成自己的数据,打开R,点Run,可以直接出图!文件适合有R语言基础的同学。

    福克斯初级和猎犬初级电线追踪工具包使用说明书

    福克斯初级和猎犬初级电线追踪工具包使用说明书

    数据库实验报告 SJK完整性语言

    数据库实验报告 SJK完整性语言

    PDU8000 ATS配电箱-T 快速指南

    PDU8000 ATS配电箱-T 快速指南

    串口通过 YMODEM 协议进行文件传输

    串口协议 串口通过 YMODEM 协议进行文件传输 开发环境 框架:Qt 5.7.1 编译器:MSVC2015_64bit IDE:Qt Creator 4.2.0 社区版 操作系统:Windows 10 专业版

    springboot(题库管理系统)

    开发语言:Java JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.6/5.7(或8.0) 数据库工具:Navicat 开发软件:idea 依赖管理包:Maven 代码+数据库保证完整可用,可提供远程调试并指导运行服务(额外付费)~ 如果对系统的中的某些部分感到不合适可提供修改服务,比如题目、界面、功能等等... 声明: 1.项目已经调试过,完美运行 2.需要远程帮忙部署项目,需要额外付费 3.本项目有演示视频,如果需要观看,请联系我 4.调试过程中可帮忙安装IDEA,eclipse,MySQL,JDK,Tomcat等软件 重点: 需要其他Java源码联系我,更多源码任你选,你想要的源码我都有! https://img-blog.csdnimg.cn/direct/e73dc0ac8d27434b86d886db5a438c71.jpeg

    SITOP 电源电源电源电源 20 6EP1 536-2AA00 操作手册

    SITOP 电源电源电源电源 20 6EP1 536-2AA00 操作手册

Global site tag (gtag.js) - Google Analytics