Вы находитесь на странице: 1из 53

Beginning Rust: From Novice to

Professional Carlo Milanesi


Visit to download the full and correct content document:
https://textbookfull.com/product/beginning-rust-from-novice-to-professional-carlo-mila
nesi/
More products digital (pdf, epub, mobi) instant
download maybe you interests ...

Beginning Rust: From Novice to Professional 1st Edition


Carlo Milanesi

https://textbookfull.com/product/beginning-rust-from-novice-to-
professional-1st-edition-carlo-milanesi/

Beginning Python: From Novice to Professional Magnus


Lie Hetland

https://textbookfull.com/product/beginning-python-from-novice-to-
professional-magnus-lie-hetland/

Beginning Rails 6: From Novice to Professional Brady


Somerville

https://textbookfull.com/product/beginning-rails-6-from-novice-
to-professional-brady-somerville/

Beginning SQL Queries From Novice to Professional Clare


Churcher

https://textbookfull.com/product/beginning-sql-queries-from-
novice-to-professional-clare-churcher/
Beginning Spring 5: From Novice to Professional Joseph
B. Ottinger

https://textbookfull.com/product/beginning-spring-5-from-novice-
to-professional-joseph-b-ottinger/

Beginning Perl Programming: From Novice to Professional


William "Bo" Rothwell

https://textbookfull.com/product/beginning-perl-programming-from-
novice-to-professional-william-bo-rothwell/

Beginning Python: From Novice to Professional, 3rd


Edition Magnus Lie Hetland

https://textbookfull.com/product/beginning-python-from-novice-to-
professional-3rd-edition-magnus-lie-hetland/

Beginning Rails 6: From Novice to Professional 4th


Edition Brady Somerville

https://textbookfull.com/product/beginning-rails-6-from-novice-
to-professional-4th-edition-brady-somerville/

Beginning C++20: From Novice to Professional - Sixth


Edition Ivor Horton

https://textbookfull.com/product/beginning-c20-from-novice-to-
professional-sixth-edition-ivor-horton/
Beginning
Rust
From Novice to Professional

Carlo Milanesi
Beginning Rust
From Novice to Professional

Carlo Milanesi
Beginning Rust: From Novice to Professional
Carlo Milanesi
Bergamo, Italy
ISBN-13 (pbk): 978-1-4842-3467-9 ISBN-13 (electronic): 978-1-4842-3468-6
https://doi.org/10.1007/978-1-4842-3468-6
Library of Congress Control Number: 2018935885

Copyright © 2018 by Carlo Milanesi


This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the
trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Steve Anglin
Development Editor: Matthew Moodie
Coordinating Editor: Mark Powers
Cover designed by eStudioCalamar
Cover image designed by Freepik (www.freepik.com)
Distributed to the book trade worldwide by Springer Science+Business Media New York,
233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail
orders-ny@springer-sbm.com, or visit www.springeronline.com. Apress Media, LLC is a California LLC and
the sole member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM
Finance Inc is a Delaware corporation.
For information on translations, please e-mail editorial@apress.com; for reprint, paperback, or audio rights,
please email bookpermissions@springernature.com.
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available to
readers on GitHub via the book’s product page, located at www.apress.com/9781484234679. For more
detailed information, please visit http://www.apress.com/source-code.
Printed on acid-free paper
Table of Contents
About the Author��������������������������������������������������������������������������������������������������� xiii

About the Technical Reviewer���������������������������������������������������������������������������������xv


Preface������������������������������������������������������������������������������������������������������������������xvii

Chapter 1: Printing on the Terminal������������������������������������������������������������������������� 1


How to Start���������������������������������������������������������������������������������������������������������������������������������� 1
Hello, World!���������������������������������������������������������������������������������������������������������������������������������� 2
Printing Combinations of Literal Strings��������������������������������������������������������������������������������������� 4
Printing Several Lines of Text�������������������������������������������������������������������������������������������������������� 5
Printing Integer Numbers�������������������������������������������������������������������������������������������������������������� 6
Command-Line Script������������������������������������������������������������������������������������������������������������������� 7
Comments������������������������������������������������������������������������������������������������������������������������������������� 8

Chapter 2: Doing Arithmetic������������������������������������������������������������������������������������� 9


Adding Integer Numbers��������������������������������������������������������������������������������������������������������������� 9
Other Operations Between Integer Numbers������������������������������������������������������������������������������ 10
Floating-Point Arithmetic������������������������������������������������������������������������������������������������������������ 11
Sequences of Statements����������������������������������������������������������������������������������������������������������� 13
Breaking Literal Strings�������������������������������������������������������������������������������������������������������������� 14

Chapter 3: Naming Objects������������������������������������������������������������������������������������� 17


Associating Names to Values������������������������������������������������������������������������������������������������������ 17
Mutable Variables����������������������������������������������������������������������������������������������������������������������� 19
Not Mutated Mutable Variables��������������������������������������������������������������������������������������������������� 21
Uninitialized Variables����������������������������������������������������������������������������������������������������������������� 22
The Leading Underscore������������������������������������������������������������������������������������������������������������� 23

iii
Table of Contents

Boolean Values���������������������������������������������������������������������������������������������������������������������������� 25
Boolean Expressions������������������������������������������������������������������������������������������������������������������� 27
Type Consistency in Assignments����������������������������������������������������������������������������������������������� 28
Change of Type and of Mutability������������������������������������������������������������������������������������������������ 29
Assignment Arithmetic Operators����������������������������������������������������������������������������������������������� 30
Using the Functions of the Standard Library������������������������������������������������������������������������������ 31

Chapter 4: Controlling Execution Flow������������������������������������������������������������������� 33


Conditional Statements (if)��������������������������������������������������������������������������������������������������������� 33
Conditional Expressions�������������������������������������������������������������������������������������������������������������� 36
Conditioned Loops (while)����������������������������������������������������������������������������������������������������������� 38
Infinite Loops (loop)�������������������������������������������������������������������������������������������������������������������� 40
Counting Loops (for)�������������������������������������������������������������������������������������������������������������������� 40
Variables Scopes������������������������������������������������������������������������������������������������������������������������� 42

Chapter 5: Using Data Sequences��������������������������������������������������������������������������� 47


Arrays������������������������������������������������������������������������������������������������������������������������������������������ 47
Mutable Arrays���������������������������������������������������������������������������������������������������������������������������� 50
Arrays of Specified Size�������������������������������������������������������������������������������������������������������������� 51
Multidimensional Arrays������������������������������������������������������������������������������������������������������������� 52
Vectors���������������������������������������������������������������������������������������������������������������������������������������� 53
Other Operations on Vectors������������������������������������������������������������������������������������������������������� 56
Empty Arrays and Vectors����������������������������������������������������������������������������������������������������������� 57
Debug Print��������������������������������������������������������������������������������������������������������������������������������� 58
Copying Arrays and Vectors�������������������������������������������������������������������������������������������������������� 59

Chapter 6: Using Primitive Types���������������������������������������������������������������������������� 61


Non-Decimal Numeric Bases������������������������������������������������������������������������������������������������������ 62
Underscore in Numeric Literals�������������������������������������������������������������������������������������������������� 63
The Exponential Notation������������������������������������������������������������������������������������������������������������ 64
The Various Kinds of Signed Integer Numbers���������������������������������������������������������������������������� 65

iv
Table of Contents

Unsigned Integer Number Types������������������������������������������������������������������������������������������������� 68


Target-Dependent Integer-Number Types����������������������������������������������������������������������������������� 68
Type Inference����������������������������������������������������������������������������������������������������������������������������� 70
The Type Inference Algorithm����������������������������������������������������������������������������������������������������� 72
Floating-Point Numeric Types����������������������������������������������������������������������������������������������������� 73
Explicit Conversions�������������������������������������������������������������������������������������������������������������������� 74
Type Suffixes of Numeric Literals����������������������������������������������������������������������������������������������� 75
All the Numeric Types����������������������������������������������������������������������������������������������������������������� 76
Booleans and Characters������������������������������������������������������������������������������������������������������������ 77
The Empty Tuple�������������������������������������������������������������������������������������������������������������������������� 79
Array and Vector Types��������������������������������������������������������������������������������������������������������������� 80
Constants������������������������������������������������������������������������������������������������������������������������������������ 81
Discovering the Type of an Expression��������������������������������������������������������������������������������������� 81

Chapter 7: Enumerating Cases������������������������������������������������������������������������������� 83


Enumerations������������������������������������������������������������������������������������������������������������������������������ 83
The match Construct������������������������������������������������������������������������������������������������������������������� 85
Relational Operators and Enums������������������������������������������������������������������������������������������������� 87
Handling All the Cases���������������������������������������������������������������������������������������������������������������� 88
Using match with Numbers��������������������������������������������������������������������������������������������������������� 89
Enumerations with Data�������������������������������������������������������������������������������������������������������������� 90
“match” Expressions������������������������������������������������������������������������������������������������������������������ 94
Use of Guards in match Constructs��������������������������������������������������������������������������������������������� 94

Chapter 8: Using Heterogeneous Data Structures�������������������������������������������������� 97


The Tuples����������������������������������������������������������������������������������������������������������������������������������� 97
The Structs���������������������������������������������������������������������������������������������������������������������������������� 99
The Tuple-Structs���������������������������������������������������������������������������������������������������������������������� 102
Lexical Conventions������������������������������������������������������������������������������������������������������������������ 103

v
Table of Contents

Chapter 9: Defining Functions������������������������������������������������������������������������������ 105


Defining and Invoking a Function��������������������������������������������������������������������������������������������� 105
Functions Defined After Their Use��������������������������������������������������������������������������������������������� 106
Functions Shadowing Other Functions������������������������������������������������������������������������������������� 107
Passing Arguments to a Function��������������������������������������������������������������������������������������������� 108
Passing Arguments by Value����������������������������������������������������������������������������������������������������� 110
Returning a Value from a Function������������������������������������������������������������������������������������������� 111
Early Exit����������������������������������������������������������������������������������������������������������������������������������� 112
Returning Several Values���������������������������������������������������������������������������������������������������������� 114
How to Change a Variable of the Caller������������������������������������������������������������������������������������� 115
Passing Arguments by Reference��������������������������������������������������������������������������������������������� 116
Using References���������������������������������������������������������������������������������������������������������������������� 118
Mutability of References����������������������������������������������������������������������������������������������������������� 119

Chapter 10: Defining Generic Functions and Structs�������������������������������������������� 121


Need of Generic Functions�������������������������������������������������������������������������������������������������������� 121
Defining and Using Generic Functions�������������������������������������������������������������������������������������� 122
Inferring the Parametric Types�������������������������������������������������������������������������������������������������� 124
Defining and Using Generic Structs������������������������������������������������������������������������������������������ 125
Genericity Mechanics���������������������������������������������������������������������������������������������������������������� 126
Generic Arrays and Vectors������������������������������������������������������������������������������������������������������� 129
Generic Enums�������������������������������������������������������������������������������������������������������������������������� 129
Error Handling��������������������������������������������������������������������������������������������������������������������������� 131
Enum Standard Utility Functions����������������������������������������������������������������������������������������������� 133

Chapter 11: Allocating Memory���������������������������������������������������������������������������� 135


The Various Kinds of Allocation������������������������������������������������������������������������������������������������� 135
Linear Addressing��������������������������������������������������������������������������������������������������������������������� 136
Static Allocation������������������������������������������������������������������������������������������������������������������������ 138
Stack Allocation������������������������������������������������������������������������������������������������������������������������ 139
Limitations of Stack Allocation�������������������������������������������������������������������������������������������������� 145

vi
Table of Contents

Heap Allocation������������������������������������������������������������������������������������������������������������������������� 148


Heap Management�������������������������������������������������������������������������������������������������������������������� 149
The Behavior of Box������������������������������������������������������������������������������������������������������������������ 150
Similarity with C and C++��������������������������������������������������������������������������������������������������������� 151
Boxing and Unboxing���������������������������������������������������������������������������������������������������������������� 152
Register Allocation�������������������������������������������������������������������������������������������������������������������� 153

Chapter 12: Data Implementation������������������������������������������������������������������������� 155


Discovering the Size of Objects������������������������������������������������������������������������������������������������ 155
The use Directive���������������������������������������������������������������������������������������������������������������������� 156
The Sizes of the Primitive Types����������������������������������������������������������������������������������������������� 157
The Representation of Primitive Types�������������������������������������������������������������������������������������� 158
Location of Bytes in Memory���������������������������������������������������������������������������������������������������� 159
Sizes of Composite Data Types������������������������������������������������������������������������������������������������� 161
Vector Allocation����������������������������������������������������������������������������������������������������������������������� 162

Chapter 13: Defining Closures������������������������������������������������������������������������������ 165


The Need for “Disposable” Functions��������������������������������������������������������������������������������������� 165
Capturing the Environment������������������������������������������������������������������������������������������������������� 167
Closures������������������������������������������������������������������������������������������������������������������������������������ 168
Other Examples������������������������������������������������������������������������������������������������������������������������� 170

Chapter 14: Using Changeable Strings����������������������������������������������������������������� 173


Static Strings���������������������������������������������������������������������������������������������������������������������������� 173
Dynamic Strings������������������������������������������������������������������������������������������������������������������������ 176
Implementation of String���������������������������������������������������������������������������������������������������������� 177
Creating Strings������������������������������������������������������������������������������������������������������������������������ 179
Concatenating Strings��������������������������������������������������������������������������������������������������������������� 180

Chapter 15: Ranges and Slices����������������������������������������������������������������������������� 183


The Ranges������������������������������������������������������������������������������������������������������������������������������� 183
Passing a Sequence to a Function�������������������������������������������������������������������������������������������� 185
The Slices��������������������������������������������������������������������������������������������������������������������������������� 187

vii
Table of Contents

Slicing��������������������������������������������������������������������������������������������������������������������������������������� 190
Out-of-Range Slicing����������������������������������������������������������������������������������������������������������������� 191
Mutable Slicing������������������������������������������������������������������������������������������������������������������������� 192
Open-Ended Ranges and Slicing����������������������������������������������������������������������������������������������� 193

Chapter 16: Using Iterators���������������������������������������������������������������������������������� 197


String Characters���������������������������������������������������������������������������������������������������������������������� 197
Scanning a String���������������������������������������������������������������������������������������������������������������������� 199
Using Iterators in for Loops������������������������������������������������������������������������������������������������������� 201
Iterations Without Mutation������������������������������������������������������������������������������������������������������� 204
Iterations with Mutation������������������������������������������������������������������������������������������������������������ 205
An Iterator Adapter: filter����������������������������������������������������������������������������������������������������������� 209
The map Iterator Adapter���������������������������������������������������������������������������������������������������������� 210
The enumerate Iterator Adapter������������������������������������������������������������������������������������������������ 211
An Iterator Consumer: any�������������������������������������������������������������������������������������������������������� 212
The all Iterator Consumer��������������������������������������������������������������������������������������������������������� 214
The count Iterator Consumer���������������������������������������������������������������������������������������������������� 215
The sum Iterator Consumer������������������������������������������������������������������������������������������������������ 215
The min and max Iterator Consumers��������������������������������������������������������������������������������������� 216
The collect Consumer��������������������������������������������������������������������������������������������������������������� 217
Iterator Chains�������������������������������������������������������������������������������������������������������������������������� 219
Iterators Are “Lazy”������������������������������������������������������������������������������������������������������������������� 220

Chapter 17: Input/Output and Error Handling������������������������������������������������������� 223


Command-Line Arguments������������������������������������������������������������������������������������������������������� 223
Process Return Code����������������������������������������������������������������������������������������������������������������� 224
Environment Variables�������������������������������������������������������������������������������������������������������������� 225
Reading from the Console��������������������������������������������������������������������������������������������������������� 226
Proper Runtime Error Handling������������������������������������������������������������������������������������������������� 228
Writing to the Console��������������������������������������������������������������������������������������������������������������� 231

viii
Table of Contents

Converting a Value to a String�������������������������������������������������������������������������������������������������� 232


File Input/Output����������������������������������������������������������������������������������������������������������������������� 233
Processing Text Files����������������������������������������������������������������������������������������������������������������� 235

Chapter 18: Using Traits��������������������������������������������������������������������������������������� 239


The Need for Traits�������������������������������������������������������������������������������������������������������������������� 239
Traits to the Rescue������������������������������������������������������������������������������������������������������������������ 242
Generic Functions with No Trait Bounds����������������������������������������������������������������������������������� 244
Scope of Traits�������������������������������������������������������������������������������������������������������������������������� 246
Traits with Multiple Functions��������������������������������������������������������������������������������������������������� 247
Methods������������������������������������������������������������������������������������������������������������������������������������ 250
The “self” and “Self” Keywords������������������������������������������������������������������������������������������������ 252
Standard Traits�������������������������������������������������������������������������������������������������������������������������� 254
The “Iterator” Trait�������������������������������������������������������������������������������������������������������������������� 255
The “type” Keyword������������������������������������������������������������������������������������������������������������������ 258
Generic Traits���������������������������������������������������������������������������������������������������������������������������� 259
Using Associated Types to Simplify Generic Traits Use������������������������������������������������������������� 264
The “Iterator” Standard Trait Declaration���������������������������������������������������������������������������������� 267
Using Generic Iterators������������������������������������������������������������������������������������������������������������� 270

Chapter 19: Object-Oriented Programming���������������������������������������������������������� 273


Inherent Implementations��������������������������������������������������������������������������������������������������������� 273
Peculiarities of Rust Object-Orientation������������������������������������������������������������������������������������ 277
Mutating Methods��������������������������������������������������������������������������������������������������������������������� 281
Constructors������������������������������������������������������������������������������������������������������������������������������ 282
Composition Instead of Inheritance������������������������������������������������������������������������������������������ 283
Memory Usage of Composition������������������������������������������������������������������������������������������������� 286
Static Dispatch�������������������������������������������������������������������������������������������������������������������������� 286
Dynamic Dispatch��������������������������������������������������������������������������������������������������������������������� 290
Implementation of References to Traits������������������������������������������������������������������������������������ 292
Static vs. Dynamic Dispatch����������������������������������������������������������������������������������������������������� 293

ix
Table of Contents

Chapter 20: Standard Library Collections������������������������������������������������������������� 295


Collections�������������������������������������������������������������������������������������������������������������������������������� 295
Measuring Execution Time�������������������������������������������������������������������������������������������������������� 296
Performing Arbitrary Insertions and Removals������������������������������������������������������������������������� 297
Queues�������������������������������������������������������������������������������������������������������������������������������������� 300
Linked Lists������������������������������������������������������������������������������������������������������������������������������� 303
Binary Heaps����������������������������������������������������������������������������������������������������������������������������� 304
Ordered Sets and Unordered Sets��������������������������������������������������������������������������������������������� 306
Ordered Dictionaries and Unordered Dictionaries��������������������������������������������������������������������� 309
Collections in C++ and in Rust������������������������������������������������������������������������������������������������� 311

Chapter 21: Drops, Moves, and Copies����������������������������������������������������������������� 313


Deterministic Destruction��������������������������������������������������������������������������������������������������������� 313
Ownership��������������������������������������������������������������������������������������������������������������������������������� 316
Destructors������������������������������������������������������������������������������������������������������������������������������� 317
Assignment Semantics������������������������������������������������������������������������������������������������������������� 322
Copying vs. Moving Performance��������������������������������������������������������������������������������������������� 324
Moving and Destroying Objects������������������������������������������������������������������������������������������������ 327
Need for Copy Semantics���������������������������������������������������������������������������������������������������������� 330
Cloning Objects������������������������������������������������������������������������������������������������������������������������� 331
Making Types Cloneable or Copyable���������������������������������������������������������������������������������������� 333

Chapter 22: Borrowing and Lifetimes������������������������������������������������������������������� 337


Ownership and Borrowing�������������������������������������������������������������������������������������������������������� 337
Object Lifetimes������������������������������������������������������������������������������������������������������������������������ 338
Errors Regarding Borrowing����������������������������������������������������������������������������������������������������� 340
How to Prevent “Use After Drop” Errors������������������������������������������������������������������������������������ 343
How to Prevent “Use After Change by an Alias” Errors������������������������������������������������������������� 344
Listing the Possible Cases of Multiple Borrowings������������������������������������������������������������������� 345
Using a Block to Restrict Borrowing Scope������������������������������������������������������������������������������ 348

x
Table of Contents

The Need of Lifetime Specifiers for Returned References�������������������������������������������������������� 349


Usage and Meaning of Lifetime Specifiers������������������������������������������������������������������������������� 352
Checking the Validity of Lifetime Specifiers����������������������������������������������������������������������������� 355
Using the Lifetime Specifiers of Invoked Functions������������������������������������������������������������������ 358

Chapter 23: More About Lifetimes������������������������������������������������������������������������ 361


Lifetime Elision������������������������������������������������������������������������������������������������������������������������� 361
Lifetime Elision with Object-Oriented Programming����������������������������������������������������������������� 363
The Need of Lifetime Specifiers for Structs������������������������������������������������������������������������������ 363
Possible Lifetime Specifiers for Structs������������������������������������������������������������������������������������ 366
Other Uses of Lifetime Specifiers��������������������������������������������������������������������������������������������� 368

Index��������������������������������������������������������������������������������������������������������������������� 371

xi
About the Author
Carlo Milanesi is a professional software developer and
expert in C++, graphics programming, and GUI design. He
graduated from the State University of Milan and worked in
the financial and CAD/CAM software industries. He enjoys
writing software in Smalltalk and Rust.

xiii
About the Technical Reviewer
Massimo Nardone has more than 24 years of experience
in Security, Web/Mobile development, Cloud, and IT
Architecture. His true IT passions are Security and Android.
He has been programming and teaching how to program
with Android, Perl, PHP, Java, VB, Python, C/C++, and
MySQL for more than 20 years.
He holds a Master of Science degree in Computing
Science from the University of Salerno, Italy.
He has worked as a Project Manager, Software Engineer,
Research Engineer, Chief Security Architect, Information
Security Manager, PCI/SCADA Auditor, and Senior Lead IT
Security/Cloud/SCADA Architect for many years.
Technical skills include Security, Android, Cloud, Java, MySQL, Drupal, Cobol, Perl,
Web and Mobile development, MongoDB, D3, Joomla, Couchbase, C/C++, WebGL,
Python, Pro Rails, Django CMS, Jekyll, Scratch, etc.
He has worked as a visiting lecturer and supervisor for exercises at the Networking
Laboratory of the Helsinki University of Technology (Aalto University). He holds four
international patents (PKI, SIP, SAML, and Proxy areas).
He currently works as the Chief Information Security Officer (CISO) for Cargotec Oyj
and is a member of the ISACA Finland chapter board.

xv
Preface
This book teaches a beginner how to program with the Rust programming language in
an easy, step-by-step manner.
Only a basic knowledge of programming is required, preferably in the C or C++
languages. Let's say that to understand this text it's enough to know what an integer is
and what a floating-point number is, and to distinguish identifiers from string literals.
A command-line environment is assumed, like a Unix or Linux shell, Mac OS
Terminal, or Windows Command Prompt.
Please note that this book does not cover everything needed to develop professional
programs in Rust. It just teaches the difficult concepts needed to understand more
advanced texts, like the official tutorial of the language.

xvii
CHAPTER 1

Printing on the Terminal


In this chapter, you will learn:

• How to write and run your first program in the Rust Language

• How to output texts and numbers on the terminal

• How to write a small script that makes more readable the output of
the compiler

• How to write comments in your code

H
 ow to Start
The smallest valid Rust program is:

fn main(){}

Of course, it does nothing. It just defines an empty function named “main”.


By “function” we mean a set of instructions that does something and that has been
given a name.
The "fn" word is shorthand for “function”. The "main" word is the name of the
function. The round parentheses contain the possible arguments of the function; in this
case there are no arguments. To close, the braces contain the possible statements that
comprise the body of the function; in this case there is no statement.
When a program written in Rust is run, its “main” function is executed. If there is no
“main” function, then it isn’t a complete program; it may be a library, though.

1
© Carlo Milanesi 2018
C. Milanesi, Beginning Rust, https://doi.org/10.1007/978-1-4842-3468-6_1
Chapter 1 Printing on the Terminal

To run this program, complete the following actions:

• Install the package containing the Rust compiler and its utilities.
A compiler can be downloaded for free from the website https://
www.rust-lang.org. Linux, Windows, or macOS platforms, with
processor architecture x86 (32-bit) or x86-64 (64-bit), are available.
For each platform, there are three versions: “stable”, “beta”, and
“nightly”. The “stable” version is recommended; it is the oldest, but
also the most tested and the one less likely to change. All of these
program versions should be used from the command line of a
console. After installation, to check which version is installed, type at
a command line (with uppercase V): rustc -V.

• Create or choose a folder where your Rust exercises will be stored and,
using any text editor, create in that folder a file named "main.rs",
having the above contents.

• At a command line, in the folder, type: rustc main.rs. The prompt


should be printed almost immediately, after having created a file
named "main" (in a Windows environment, it will be named "main.
exe"). Actually, the "rustc" command has correctly compiled the
specified file. That is, it has read it and generated the corresponding
machine code, and it has stored this machine code in a file in the
same folder.

• At the command line, if in a Windows environment, type: main For


other operating systems, type: ./main. You just run the program
generated before, but the prompt should be printed immediately, as
this program does nothing.

Hello, World!
Let's see how to print some text on the terminal. Change the program of the previous
section to the following:

fn main() {
    print!("Hello, world!");
}

2
Chapter 1 Printing on the Terminal

If it is compiled and run as before, it prints: "Hello, world!"


Notice that the newly added line contains eight syntax items, aka “tokens”. Let’s
examine them:

• print: It is the name of a macro defined in the Rust standard library.

• !: It specifies that the preceding name indicates a macro. Without


such a symbol, print would instead indicate a function. There is no
such function in the Rust standard library, and so you would get a
compilation error. A macro is a thing similar to a function - it’s some
Rust code to which a name is associated. By using this name, you ask
to insert such code in this point.

• (: It starts the list of arguments of the macro.

• ": it starts the literal string.

• Hello, world!: It is the content of the literal string.

• ": It ends the literal string.

• ): It ends the list of the arguments of the macro.

• ;: It ends the statement.

Let’s examine the meaning of the “literal string” phrase. The word “string” means
“finite sequence of characters, possibly including spaces and punctuation”. The word
“literal” means “with a value specified directly in source code.” Therefore a “literal
string” is a “finite sequence of characters (possibly including spaces and punctuation)
specified directly in source code”.
The print macro simply inserts some code that prints on the terminal the text that is
received as an argument.
Rust always distinguishes between uppercase and lowercase letters - it’s “case
sensitive”. For all characters that are outside literal strings and comments, if you
replace some uppercase letter with a lowercase one or conversely, typically you get a
compilation error, or anyway a program with a different behavior. Instead, making such
errors inside literal strings always allows a successful compilation, but it's likely the
behavior of the program will be different.

3
Chapter 1 Printing on the Terminal

For example:

fn Main() {}

If you compile this program, you get the compilation error "main function not
found", as no main function (with a lowercase m) is defined in the program.
From now on, except when specified, we will assume the example code will be inside
the braces of the “main” function, and so the braces and the text preceding them will be
omitted.

Printing Combinations of Literal Strings


Instead of using a single literal string, you can print several of them, even in a single
statement. In this way:

print!("{}, {}!", "Hello", "world");

This statement, put inside the braces of the “main” function, will print again:
"Hello, world!".
In this case, the print macro receives three arguments, separated by commas.
All three arguments are literal strings. The first string, though, contains two pairs of
braces ({}). They are placeholders, indicating the positions in which to insert the other
two strings.
So, the macro scans the arguments after the first one, and for each of them it
looks inside the first argument for a pair of braces, and replaces them with the current
argument.
This resembles the following C language statement:

printf("%s, %s!", "Hello", "world");

But there is an important difference. If you try to compile

print!("{}, !", "Hello", "world");

you get the compilation error "argument never used", as the arguments of the macro
after the first one are more numerous than the placeholders inside the first argument;
that is, there is some argument that doesn't have any corresponding placeholder.
And if you try to compile

print!("{}, {}!", "Hello");

4
Chapter 1 Printing on the Terminal

you get a compilation error too, as the placeholders inside the first argument are more
numerous than the arguments after the first argument; that is, there is a placeholder that
doesn't have any corresponding argument.
Instead, the corresponding statements in the C language do not raise compilation
errors, but instead cause the compiled program to crash or misbehave.

Printing Several Lines of Text


So far, we wrote programs that print only one line. But a single statement can print
several lines; in this way:

print!("First line\nSecond line\nThird line\n");

This will print:

First line
Second line
Third line

The sequence of characters \n, where n stands for “new line”, is transformed by
the compiler into the character sequence that represents the line terminator for the
currently used operating system.
Given that it is very common to go to a new line only once for every printing
statement, and just at the end of the statement, another macro, "println", has been
added to the Rust standard library. It’s used in this way:

println!("text of the line");

This statement is equivalent to:

print!("text of the line\n");

Calling this println macro (whose name is to be read “print line”) is equivalent to
calling print with the same arguments, and then outputting a line terminator.

5
Chapter 1 Printing on the Terminal

Printing Integer Numbers


If we want to print an integer number, we can type:

print!("My number: 140");

or, using a placeholder and an additional argument:

print!("My number: {}", "140");

or, removing the quotes around the second argument:

print!("My number: {}", 140);

All these statements will print: "My number: 140".


In the last statement, the second argument is not a literal string, but it is a “literal
integer number”, or, for short, a “literal integer”.
The integers are another data type, with respect to strings.
Even for integers, the print macro is able to use them to replace the corresponding
placeholder inside its first argument.
In fact, the compiler interprets the string 140 contained in the source code as a
number expressed in decimal format, it generates the equivalent number in binary
format, and then it saves it into the executable program.
At runtime, the program takes such number in binary format, it transforms it into
the string "140", using the decimal notation, then it replaces the placeholder with that
string, so generating the string to print, and finally it sends the string to the terminal.
This procedure explains, for example, why if the following program is written:

print!("My number: {}", 000140);

the compiler generates exactly the same executable program generated before. Actually,
when the source string 000140 is converted to the binary format, the leading zeros are
ignored.
The argument types may be mixed too. This statement

print!("{}: {}", "My number", 140);

will print the same line as before. Here the first placeholder corresponds to a literal
string, while the second one to a literal integer.

6
Chapter 1 Printing on the Terminal

Command-Line Script
The rustc command shown above has a drawback: it prints all the errors it finds in your
code in the order in which it finds them. Well, often your code will contain many syntax
errors, and you should process them from the first one to the last one. But after the
compiler has finished printing the errors, you are faced with the new prompt preceded
by the last error found. So, you have to scroll back to the first error.
A way to improve this situation is to use a command-line script, whose syntax
depends on the operating system.
In a Linux system, you can put the following lines in a new script file:

clear
rustc $* --color always 2>&1 | more

In a Windows system, you can put the following three lines in a .BAT file:

@echo off
cls
rustc %* --color always 2>&1 | more

If the script file is named, say, rs (rs.bat on Windows), to compile a file named
main.rs you can type:

rs main.rs

This script first clears the screen, then runs the rustc compiler with all the
arguments you give to it. If the compilation is successful, or if it generates less than a
screenful of error messages, it behaves like a normal run of rustc.
Otherwise, it fills the screen with error messages, and then stops, and shows the
message --More-- at the bottom of the terminal screen. At this point you can press:
• The Enter key, to advance by one line.

• The Space key, to advance by one screenful.

• The Q key (for “quit”), to abort printing error messages, and get back
to the command prompt.

7
Chapter 1 Printing on the Terminal

Comments
Write the following code

// This program
// prints a number.
print!("{}", 34); // thirty-four
/* print!("{}", 80);
*/

that will print 34.


The first two lines start with a pair of slashes “//”. Such a pair of characters indicates
the start of a “line comment,” ending at the end of the line. To write a comment on
several lines, the pair of slashes must be repeated at every line of the comment, as in the
second line of the program above.
Rust programmers use to leave a blank just after the double slash, to improve
readability.
As it appears in the third line, a line comment may start after a statement, usually
separated by at least one blank.
There is another kind of comment, exemplified in the fourth and fifth lines. Such a
comment starts with the character pair “/*” and ends with the pair “*/”; it may extend on
several lines, and so it is named “multi-line comment.”
Rust programmers usually avoid the multi-line comment in production code, using
only single line comments, and use multi-line comments only to exclude temporarily
some code from compilation.
Rust comments look identical to modern C language comments. In fact, there is an
important difference between Rust comments and C comments: Rust comments may be
nested, and they must be nested correctly.

/* This is /* a valid*/
comment, even /* if /* it contains
comments*/ inside */itself.  */

/* This /* instead is not allowed in Rust,


while in C is tolerated (but it may generate a warning).*/

8
CHAPTER 2

Doing Arithmetic
In this chapter, you will learn:

• How to compute an arithmetic operation between integer numbers


or between floating-point numbers

• How to write a program containing several statements

• How to print strings in several lines

Adding Integer Numbers


Let’s see how to compute the sum of two integer numbers; for example, 80 and 34.
Put the following line as the only contents of the braces of the main function:

print!("The sum is {}.", 80 + 34);

The execution will print: "The sum is 114.".


The second argument of the print macro is the expression 80 + 34.
The compiler surely does not store in the executable such numbers in decimal
format. If compiling optimizations are off, the compiler just converts the two numbers
in binary format and stores into the executable such binary numbers and the addition
operation. But if compiling optimizations are on, the compiler, realizing that this
expression contains only constant values, evaluates directly that expression, obtaining
the integer number 114, and stores into the executable program such number in binary
format. In both cases, at runtime, such a number is formatted as the three-character
decimal string 114, and then the placeholder {} of the literal string is replaced by such
string. Finally, of course, the resulting string is printed to the console.
Notice that the string "The sum is 114." has been generated by the program; it is
not present in source code; so it is still a string, but not a literal string.

9
© Carlo Milanesi 2018
C. Milanesi, Beginning Rust, https://doi.org/10.1007/978-1-4842-3468-6_2
Chapter 2 Doing Arithmetic

Similarly, the two-character sequence 80 represents an integer number directly in


source code, and so it is called a “literal integer”. The same holds for the two characters 34.
Instead, the integer number 114, saved into the executable in binary format, and loaded
into memory at runtime, is not a literal integer, as it does not appear in source code.
It is also allowed to write:

print!("{} + {} = {}", 34, 80, 80 + 34);

whose execution will print "34 + 80 = 114".


In such case, the second argument of the macro will be put where there is the first
placeholder, the third argument where there is the second placeholder, and the fourth
argument where there is the third placeholder.
You can specify hundreds of arguments for the “print” macro, as long as the
arguments after the first one are as many as the placeholders “{}” inside the first
argument.

Other Operations Between Integer Numbers


All the integer arithmetic operators of C language can be used. For example:

print!("{}", (23 - 6) % 5 + 20 * 30 / (3 + 4));

This will print 87.


Let’s see why.
Such a formula is evaluated by the Rust compiler exactly as the C compiler would.
First, the operations in parentheses, 23 - 6 and 3 + 4, are evaluated, obtaining,
respectively, 17 and 7.
At this point, our expression has become 17 % 5 + 20 * 30 / 7.
Then, the multiplication and division operations are evaluated, as they have
precedence over addition and subtraction, and, for operations of the same precedence,
they are evaluated in order from left to right.
17 % 5 is the “remainder of the integer division” operation, and it has 2 as a result,
that is, the remainder of the operation 17 / 5. The expression 20 * 30 is evaluated
before the following division, as it is at its left.
At this point, our expression has become 2 + 600 / 7.

10
Chapter 2 Doing Arithmetic

Then, the integer division (with truncation) 600 / 7 is performed, and our
expression has become 2 + 85.
Finally, the sum is evaluated, the result is formatted in decimal notation, the
placeholder is replaced by the formatted number, and the resulting string is printed.
These arithmetic operations are performed always on integer binary numbers,
obtaining integer binary numbers, and the results are converted to decimal format only
when they are used to replace the placeholders.
Usually, compilers generate machine language instructions, which are afterwards
executed when the program is running; though, the Rust compiler is highly optimizing,
and so it tries to evaluate directly at compile time the expressions that it is possible to
evaluate using the information available in source code. Our expression is made only of
literal integers, and so the whole expression will be evaluated already at compile time,
storing in the executable program only the result to print. Though, conceptually, we can
think that the computations are performed at runtime.

Floating-Point Arithmetic
Let's see how to compute the sum between two numbers with fractional parts, for
example, 80.3 and 34.9.
Replace the statement with:

print!("The sum is {}", 80.3 + 34.8);

The run will print The sum is 115.1.


Now replace in the second number only the character “8” with a “9”, obtaining:

print!("The sum is {}", 80.3 + 34.9);

The run will print The sum is 115.19999999999999.


This will surprise those who would expect 115.2 as the result.
This phenomenon happens also in many other programming languages, and
it is due to the fact that Rust, like almost every programming language, performs
computations involving non-integer numbers using the “floating-point” format. But here
we won’t treat this format any more.
Also expressions containing floating-point numbers can be evaluated:

print!("{}", (23. - 6.) % 5. + 20. * 30. / (3. + 4.));

11
Chapter 2 Doing Arithmetic

This will print 87.71428571428571.


Let's see why.
By putting a dot after a literal number, it is transformed into a literal floating-point
number, having the same value. The precedence rules are the same of integer arithmetic,
although division has a different result.
Let's see how the evaluation of the expression is performed.
The evaluation of 23. - 6. and of 3. + 4. is similar to that of integer numbers.
By evaluating 17. % 5., 2. is obtained, similarly to integer numbers. Such an
operator does not exist in C language for floating-point numbers, and it corresponds to
the expression fmod(17., 5.) of the C language.
By evaluating "20. * 30.", 600. is obtained, similarly to integer numbers.
By evaluating "600. / 7.", a floating-point number is obtained, that cannot be
exactly represented neither in binary notation nor in the decimal one. Internally, a
binary-format approximate representation is generated; if you ask Rust to convert such
number into a decimal-format approximate representation, you would get the string
85.71428571428571.
Finally, the value 2. is added to such binary number, obtaining another value that
cannot be exactly represented, which is printed in the way shown above.
Notice that, differing from C language, in Rust you cannot simply mix integer
numbers and floating-point numbers. The following statement generates a compilation
error:

print!("{}", 2.7 + 1);

A way to make it valid is to add a dot:

print!("{}", 2.7 + 1.);

However, this one is a syntax-only limitation, not an operative one, as anyway


machine code cannot sum an integer number and a floating-point number, without
before converting one of the two operands to the type of the other operand. A C
compiler, when it encounters the expression 2.7 + 1, emits implicitly the machine
language instruction to convert the integer number 1 to a floating-point number, or
better, being 1 a constant, it is converted to a floating-point number at compile time. In
Rust, such conversions must be explicit.

12
Chapter 2 Doing Arithmetic

At last, a note about the “%” operator. This is often improperly named “modulo”
(or “modulus”) operator. Well, it should be better named “remainder” operator, because
the mathematical modulo operator has a different behavior for negative numbers. The
“%” operator behaves in Rust like in C language:

print!("{} {}", -12 % 10, -1.2 % 1.);

This will print "-2 -0.19999999999999996".

Sequences of Statements
As the body of the main function, write:

print!("{} + ", 80);


print!("{} =", 34);
print!(" {}", 80 + 34);

This will print 80 + 34 = 114.


The program now contains three statements, each of them terminated by the ";"
character. Such statements are executed in order of appearance.
If the body of the main function would become

    print!("{} + ",80);print!("{} = ",34);


            print  ! ( "{}"  ,
        80     + 34 )  ;

its result wouldn't change. Actually, additional whitespaces (blanks, tabs, and line
breaks) are ignored.
However, Rust programmers have the following habits that are recommended:

• to indent lines by four spaces inside functions;

• to avoid adding several consecutive spaces inside statements;

• to avoid exceeding 80 columns, possibly splitting long statements on


several lines.

13
Chapter 2 Doing Arithmetic

Breaking Literal Strings


As said before, to avoid code lines that are too long, you can break them in any point
between syntax symbols, like in C language; though, the syntax to break a literal string is
different. This code is illegal:

println!("{}", "This"
    "is not allowed");

Actually, in Rust you cannot simply juxtapose literal strings, like in C.


Though, you can start a literal string in one line, and end it a few lines below. For
example, this is a valid program:

fn main() {
    println!("{}", "These
        are
        three lines");
}

And this is what is printed:

These
        are
        three lines

As you can see, the literal string contains all the characters that in the source file
are between the start and the end of the string, including newline characters and line
leading spaces.
Maybe this is what you want, but you can do something different:

fn main() {
    println!("{}", "This \
        is \
        just one line");
}

This will print:

This is just one line

14
Another random document with
no related content on Scribd:
27.(a) Rind and fistulous appendages Oceanapia
present; microscleres sigmata
(b) No rind; skeleton reticulate; Gellius
microscleres sigmata and/or
toxa
28.(a) Skeleton confused or formed of 29
bundles of spicules with
echinating spined styles
(b) Skeleton fibrous or reticulate, or 45
formed of short columns
(c) Skeleton formed of a dense 52
central axis, and columns
radiating from it to the surface
29.(a) Spicules of the ectosome styles Pytheas
(b) Spicules of the ectosome oxeas Clathrissa
or absent
(c) Main skeleton confused. Spanioplon
Special ectosomal skeleton
absent
30.(a) Megascleres of the 31
choanosome not differing from
those of the ectosome
(b) Megascleres of the 32
choanosome differing from
those of the ectosome
31.(a) Chelae absent. 33
(b) Chelae present 44
32.(a) Trichodragmata present Tedania
(b) Trichodragmata absent 42
Fig. 110.—Megascleres. a-l and q-s, Modifications of monaxon type. a,
Strongyle; b, tylote; c, oxea; d, tylotoxea; e, tylostyle; f, style; g, spined
tylostyle; h, sagittal triod (a triaxon form derived from monaxon); j, oxytylote;
k, anatriaene; l, protriaene; m, sterraster (polyaxon); n, radial section
through the outer part of m, showing two actines soldered together by
intervening silica; o, desma of an Anomocladine Lithistid (polyaxon); q,
crepidial strongyle, basis of rhabdocrepid Lithistid desma; r, young form of
rhabdocrepid desma, showing crepidial strongyle coated with successive
layers of silica; s, rhabdocrepid desma.

33.(a) Skeleton reticulate or fibrous 34


(b) Skeleton radiate or diffuse 37
(c) Skeleton with radiating fibres forming a Quasillina
reticulum with others crossing them at
right angles
34.(a) No microscleres 35
(b) Microscleres sigmata and/or toxa with Desmacella
or without trichodragmata
35.(a) Sponge fan- or funnel-shaped 36
(b) Sponge not fan- or funnel-shaped Hymeniacidon
36.(a) Megascleres slender and twisted Phakellia
(b) Megascleres somewhat stout, not Tragosia
twisted
37.(a) Sigmata present, skeleton diffuse Biemma
(b) Sigmata absent 38
38.(a) Skeleton more or less radiate 39
(b) Skeleton diffuse; sponge boring Cliona
39.(a) Sponge discoid with marginal fringe Halicnemia
(b) Sponge massive or stipitate without 40
marginal fringe
40.(a) Sponge body prolonged into Polymastia
mammiform projections
(b) Sponge body without mammiform 41
projections
41.(a) No microscleres. Megascleres Suberites
tylostyles with or without styles
(b) Microscleres centrotylote. Megascleres Ficulina
styles or tylostyles
42.(a) Choanosomal megascleres smooth 43
(b) Choanosomal megascleres spined Dendoryx
43.(a) Microscleres chelae and sigmata of Lissodendoryx
about the same size
(b) Chelae, if present, smaller than the Yvesia
sigmata
44.(a) Isochelae Esperiopsis
(b) Anisochelae Esperella
45.(a) Fibres or columns plumose 46
(b) Fibres or columns ectyonine 47
46.(a) Microscleres toxa Ophlitaspongia
(b) Microscleres absent Axinella
47.(a) Skeleton reticulate 48
(b) Skeleton not reticulate 49
48.(a) Microscleres present. Spicules of the Myxilla
fibre core spined
(b) Microscleres absent. Spicules of the Lissomyxilla
fibre core smooth
49.(a) Main skeleton formed of plume-like 50
columns
(b) Main skeleton formed of horny fibres Clathria
(ectyonine). Special dermal skeleton
wanting
50.(a) Dermal skeleton contains styles only Microciona
(b) Dermal skeleton contains diactine 51
spicules with or without styli
51.(a) Main skeleton columns with a core of Plumohalichondria
smooth oxeas
(b) Main skeleton columns with a core of Stylostichon
spined styles
52.(a) Central axis contains much spongin. Raspailia
Echinating spined styli present
(b) Central axis with little or no spongin. Ciocalypta
Spined styles absent. Pillars radiating
from the axis support dermal skeleton
53.(a) Ground substance between chambers Spongelia
clear; chambers pear-shaped or oval;
eurypylous
(b) Ground substance granular. Chambers 54
spherical with aphodi
54.(a) Fibres not pithed; sponge fan-shaped Leiosella
(b) Fibres pithed; sponge massive Aplysina
55.(a) Chambers long, tubular, branched Halisarca
(b) Chambers not much longer than Oscarella
broad; not branched
56.(a) Amphidiscs present Ephydatia
(b) Amphidiscs absent Spongilla

CHAPTER IX

PORIFERA (CONTINUED): REPRODUCTION, SEXUAL AND ASEXUAL—


PHYSIOLOGY—DISTRIBUTION—FLINTS
The reproductive processes of Sponges are of such great
importance in leading us to a true conception of the nature of a
sponge that we propose to treat them here in a special section. Both
sexual and asexual methods are common; the multiplication of
oscula we do not regard as an act of reproduction (p. 174).

Fig. 111.—A, amphiblastula larva of Sycon raphanus; B, later stage, showing


invagination of the flagellated cells. c.s, Segmentation cavity; ec, ectoderm;
en, endoderm. (After F. E. Schulze, from Balfour.)

A cursory glance at a collection of sponge larvae from different


groups would suggest the conclusion that they are divisible into two
wholly distinct types. One of these is the amphiblastula, and the
other the parenchymula. This was the conclusion accepted by
zoologists not long ago. We are indebted to Delage, Maas, and
Minchin for dispelling it, and showing that these types are but the
extreme terms of a continuous series of forms which have all the
same essential constitution and undergo the same metamorphosis.

The amphiblastula of Sycon raphanus (Fig. 111) consists of an


anterior half, formed of slender flagellated cells, and a posterior half,
of which the cells are large, non-flagellate, and rounded. These two
kinds of cell are arranged around a small internal cavity which is
largely filled up with amoebocytes. The flagellated cells are
invaginated into the dome of rounded cells during metamorphosis, in
fact, become the choanocytes or gastral cells; the rounded cells, on
the other hand, become the dermal cells—an astonishing fact to any
one acquainted only with Metazoan larvae.
A typical parenchymula is that of Clathrina blanca (Fig. 112). When
hatched it consists of a wall surrounding a large central cavity and
built up of flagellated cells interrupted at the hinder pole by two cells
(p.g.c)—the mother-cells of archaeocytes. Before the
metamorphosis, certain of the flagellated cells leave the wall and
sink into the central cavity, and undergoing certain changes establish
an inner mass of future dermal cells. By subsequent metamorphosis
the remaining flagellated cells become internal, not this time by
invagination, but by the included dermal cells breaking through the
wall of the larva, and forming themselves into a layer at the outside.

Fig. 112.—Median longitudinal section of parenchymula larva of Clathrina blanca.


p.g.c, Posterior granular cells—archaeocyte mother-cells. (After Minchin.)

In the larva of C. blanca, after a period of free-swimming existence,


the same three elements are thus recognisable as in that of Sycon at
the time of hatching; in the newly hatched larva of C. blanca,
however, one set of elements, the dermal cells, are not
distinguishable. The difference, then, between the two newly
hatched larvae is due to the earlier cell differentiation of the Sycon
larva.[254]

Now consider the larva of Leucosolenia. It is hatched as a


completely flagellated larva; its archaeocytes are internal (as in
Sycon); future dermal cells, recognisable as such, are absent. They
arise, as in C. blanca, by transformation of flagellated cells; but (1)
this process is confined to the posterior pole, and (2) the internal
cavity is small and filled up with archaeocytes. Consequently the
cells which have lost their flagella and become converted into dermal
cells cannot sink in as in C. blanca: they accumulate at the hinder
pole, and thus arises a larva half flagellated, half not; in fact, an
amphiblastula. Or, briefly, in Leucosolenia the larva at hatching is a
parenchymula, and when ready to fix is an amphiblastula; and,
again, the difference between the newly hatched larva and that of
Sycon is due to the earlier occurrence of cell differentiation in the
latter. What completer transitional series could be desired?

Turning to the Micromastictora, the developmental history already


sketched is fairly typical (p. 172). The differences between Mega-
and Micro-mastictoran larvae are referable mainly to the fact that the
dermal cells in the latter become at once differentiated among
themselves to form the main types of dermal cell of the adult.[255]
The metamorphosis is comparable to that of C. blanca. Among
Tetractinellida and Hexactinellida sexually produced larvae have not
been certainly identified.

Asexual reproduction takes place according to one of three types,


which may be alluded to as (1) "budding," (2) "gemmulation," (3)
formation of "asexual larvae."

By budding (Fig. 113) is meant the formation of reproductive bodies,


each of which contains differentiated elements of the various classes
found in the parent. A simple example of this is described by
Miklucho Maclay in Ascons, where the bud is merely the end of one
of the Ascon tubes which becomes pinched off and so set free.

In Leucosolenia botryoides[256] Vasseur describes a similar process;


in this, however, a strikingly distinctive feature is present (Fig. 114),
namely, the buds have an inverse orientation with respect to that of
the parent, so that the budding sponge presents a contrast to a
sponge in which multiplication of oscula has occurred. In fact, the
free distal end of the bud becomes the base of the young sponge,
and the osculum is formed at the opposite extremity, where the bud
is constricted from the parent.
Fig. 113.—Lophocalyx philippensis. The specimen bears several buds attached
to it by long tufts of spicules. (After F. E. Schulze.)

Fig. 114.—Leucosolenia botryoides. A, a piece of the Sponge laden with buds, a-


f; i, the spicules of the buds directed away from their free ends; k, the
spicules of the parent directed towards the osculum, j. B, a bud which has
been set free and has become fixed by the extremity which was free or
distal in A. (After Vasseur.)

Such a reversal of the position of the bud is noteworthy in view of its


rarity, and the case is worth reinvestigating, for in other animal
groups a bud or a regenerated part retains so constantly the same
orientation as the parent that Loeb,[257] after experimenting on the
regeneration of Coelenterata and other forms, concluded that a kind
of "polarity" existed in the tissues of certain animals.

In Oscarella lobularis[258] the buds are transparent floating bladders,


derived from little prominences on the surface of the sponge.
Scattered in the walls of the bladders are flagellated chambers,
which open into the central cavity. The vesicular nature of the buds is
doubtless an adaptation, lessening their specific gravity and so
enabling them to float to a distance from the parent.

Gemmulation.—Spongilla has already afforded us a typical example


of this process. Gemmules very similar to those of Spongilla are
known in a few marine sponges, especially in Suberites and in
Ficulina. They form a layer attached to the surface of support of the
sponge—a layer which may be single or double, or even three or
four tiers deep. A micropyle is sometimes present in the spongin
coat, sometimes absent; possibly its absence may be correlated with
the piling of one layer of gemmules on another, as this, by covering
up the micropyle, would of course render it useless. Presumably
when a micropyle is present the living contents escape through it
and leave the sponge by way of the canal system (Fig. 115).

Fig. 115.—Gemmules of Ficulina. A, vertical section of gemmules in situ; B,


vertical section of upper portion of one gemmule. m, Micropyle.

The only case besides Spongilla in which the details of development


from gemmules have been traced is that of Tethya.[259] Mere
microscopic examination of a Tethya in active reproduction would
suggest that the process was simple budding, but Maas has shown
that the offspring arise from groups of archaeocytes in the cortex,
that is to say, they are typical gemmules. As they develop they
migrate outwards along the radial spicule-bundles and are finally
freed, like the buds of the Hexactinellid Lophocalyx (Fig. 113).

The comparison of the process of development on the one hand by


gemmules, and on the other by larval development, is of some
interest.[260] In both cases two cell layers—a dermal and a gastral—
are established before the young sponge has reached a functional
state. Differences of detail in the formation of the chambers occur in
the gemmule; these find parallels in the differences in the same
process exhibited by the larvae of various groups of sponges. On the
other hand, the order of tissue differentiation is not the same in the
gemmule as in the larva.

Fig. 116.—Development of the triradiate and quadriradiate spicules of Clathrina.


(1) Three scleroblasts; (2) each has divided: the spicule is seen in their
midst; (3) addition of the fourth ray by a porocyte. p, Dermal aperture of
pore; r, fourth ray. (After Minchin.)

Of the reproduction of Tetractinellida extremely little is known.


Spermatozoa occur in the tissues in profusion and are doubtless
functional, but larvae have been seldom observed.

Fig. 117.—Three stages in the development of the triradiate spicules of Sycon


setosum. × 1200. (After Maas.)

In Hexactinellida the place of sexually produced larvae is taken by


bodies of similar origin to gemmules but with the appearance of
parenchymulae. Ijima has indeed seen a few egg-cells in
Hexactinellids.[261] He finds, however, that archaeocyte congeries
occur in abundance, and there is good reason to believe with him
that these are responsible for the numerous parenchymula-like
asexually produced larvae he has observed. The discovery of
"asexual larvae" was first made by Wilson in the Monaxonid
Esperella; in this case the asexual larva is, as far as can be
detected, identical with that developed from the fertilised egg. A
similar phenomenon, the production of apparently identical larvae by
both sexual and asexual methods, has been observed in the
Coelenterate Gonionema murbachii.[262]

Artificially, sponges may be reproduced with great advantage to


commerce by means of cuttings. Cuttings of the bath sponge are fit
to gather after a seven years' growth.

The development of the various forms of spicules is a subject about


which little is yet known. Most spicules of which the development has
been traced originate in a single dermal cell. The triradiate and
quadriradiate spicules of Homocoela (Clathrinidae), as Minchin[263]
has most beautifully shown, form an exception. Three cells co-
operate to form the triradiate; these three divide to give six before
the growth of the spicule is complete. A quadriradiate is formed from
a triradiate spicule by addition of the fourth ray, which, again, has a
separate origin in an independent cell, in fact a porocyte. The
triradiate spicules of the Sycettidae, on the other hand, originate in a
single cell,[264] but the quadriradiate spicules are formed from these
by the addition of a fourth ray in a manner similar to that which has
just been described for Clathrinidae.
Fig. 118.—Development of monaxon spicules. A, from Spongilla lacustris,
showing the single scleroblast. (After Evans.) B, a very large monaxon,
from Leucosolenia, on which many scleroblasts are at work. (After Maas.)

Monaxon spicules if not of large size undergo their entire


development within a single scleroblast (Fig. 118, A). In some cases
if their dimensions exceed certain limits, several cells take part in
their completion; some of these are derived from the division of the
original scleroblast, others are drawn from the surrounding tissue. In
Tethya, for example, and in Leucosolenia[265] the scleroblasts round
the large monaxon spicules are so numerous as to have an almost
epithelioid arrangement.

The large oxeas of Tetilla, Stelletta, and Geodia, however, are


formed each within a single scleroblast.[266]

Fig. 119.—Development of spheraster. A, of Tethya, from union of two


quadriradiate spicules. (After Maas.) B (a-e), of Chondrilla, from a spherical
globule. (After Keller.)
Triaenes have been shown[267] to originate as monaxons with one
swollen termination, from which later the cladi grow out. Information
as to the scleroblasts in this case is needed.

The value of a knowledge of the ontogeny of microscleres might be


great. Maas believes that he has shown that the spherasters of
Tethya are formed by the union of minute tetractine calthrops (Fig.
119, A). If this view should be confirmed, it would afford a very strong
argument for the Tetractinellid affinities of Tethya.

Fig. 120.—Stages in the development of the microscleres of Placospongia. (After


Keller.)

Keller,[268] on the other hand, finds that the spherasters of the


Tetractinellid Chondrilla originate as spheres (Fig. 119, B); and
spheres have been observed in the gemmule of a Tethya; no
spherasters were as yet present in the gemmule, and spheres were
absent in the adult.[269]

In the genus Placospongia certain spicules are present which


outwardly closely resemble the sterrasters so characteristic of
certain Tetractinellidae. Their development, however, as will be seen
from Fig. 120, shows that they are not polyaxon but spiny monaxon
spicules. Placospongia is consequently transferred to the
Monaxonida Spintharaphora.

Sterrasters originate within an oval cell as a number of hairlike


fibres[270] (trichites), which are united at their inner ends. The outer
ends become thickened and further modified. The position occupied
by the nucleus of the scleroblast is marked in the adult spicule by a
hilum.
Fig. 121.—Three stages in the development of an anisochela. al, Ala; al', lower
ala; f, falx; f', lower falx; r, rostrum; r', lower rostrum. (After Vosmaer and
Pekelharing.)

The anisochela has been shown repeatedly to originate from a C-


shaped spicule.[271]

What little is known of the development of Hexactinellid spicules we


owe to Ijima.[272] Numerous cells are concerned in certain later
developmental stages of the hexaster; a hexaster passes through a
hexactin stage, and—a fact "possibly of importance for the
phylogeny of spicules in Hexactinellida"—in two species the first
formed spicules are a kind of hexactin, known as a "stauractin," and
possessing only four rays all in one plane (cf. Protospongia, p. 207).

Physiology
Production of the Current.—It is not at first sight obvious that the
lashing of flagella in chambers arranged as above described,
between an inhalant and an exhalant system of canals, will
necessarily produce a current passing inwards at the ostia and
outwards at the osculum. And the difficulty seems to be increased
when it is found[273] that the flagella in any one chamber do not
vibrate in concert, but that each keeps its own time. This, however, is
of less consequence than might seem to be the case. Two conditions
are essential to produce the observed results: (1) in order that the
water should escape at the mouth of the chamber there must be a
pressure within the chamber higher than that in the exhalant
passages; (2) in order that water may enter the chamber there must
be within it a pressure less than that in the inhalant passages. But
the pressure in the inhalant and exhalant passages is presumably
the same, at any rate before the current is started, therefore there
must be a difference of pressure within the chamber itself, and the
less pressure must be round the periphery. Such a distribution of
pressures would be set up if each flagellum caused a flow of water
directed away from its own cell and towards the centre of the
chamber; and this would be true whether the flagellum beats
synchronously with its fellows or not.

The comparative study of the canal systems of sponges[274]


acquires a greater interest in proportion as the hope of correlating
modifications with increase of efficiency seems to be realised. In a
few main issues this hope may be said to have been realised. The
points, so to speak, of a good canal system are (1) high oscular
velocity, which ensures rapid removal of waste products to a
wholesome distance; (2) a slow current without eddies in the
flagellated chambers, to allow of the choanocytes picking up food
particles (see below), and moreover to prevent injury to the delicate
collars of those cells; (3) a small area of choanocytes, and
consequent small expenditure of energy in current production.

It is then at once clear at what a disadvantage the Ascons are placed


as compared with other sponges having canal systems of the
second or third types. Their chamber and oscular currents can differ
but slightly, the difference being obtained merely by narrowing the
lumen of the distal extremity of the body to form the oscular rim.
Further, the choanocytes are acting on a volume of water which they
can only imperfectly control, and it is no doubt due to the necessity
of limiting the volume of water which the choanocytes have to set in
motion that the members of the Ascon family are so restricted in
size. The oscular rim is only a special case of a device adopted by
sponges at the very outset of their career, and retained and
perfected when they have reached their greatest heights; the volume
of water passing per second over every cross-section of the path of
the current is of course the same, therefore by narrowing the cross-
sectional area of the path at any point, the velocity of the current is
proportionally increased at that point. The lining of the oscular rim is
of pinacocytes; they determine a smooth surface, offering little
frictional resistance to the current, while choanocytes in the same
position would have been a hindrance, not only by setting up friction,
but by causing irregularities in the motion.

Canal systems of the second type show a double advance upon that
of the Ascons, namely, subdivision of the gastral cavity and much
greater length of the smooth walled exhalant passage. The
choanocytes have now a task more equal to their strength, and,
further, there is now a very great inequality between the total
sectional areas of the flagellated chambers and that of the oscular
tube.

Canal systems of the third type with tubular chambers are an


improvement on those of the second, in that the area of choanocytes
is increased by the pouching of the chamber-layer without
corresponding increase in the size of the sponge. However, the area
of choanocytes represents expenditure of energy, and the next
problem to be solved is how to retain the improved current and at the
same time to cut down expense. The first step is to change the form
of the chamber from tubular to spherical. Now the energy of all the
choanocytes is concentrated on the same small volume of water.
The area of choanocytes is less, but the end result is as good as
before. At the wide mouth of the spherical chamber there is
nevertheless still a cause of loss of energy in the form of eddies, and
it is as an obviation of these that one must regard the aphodi and
prosodi with which higher members of the Demospongiae are
provided. The correctness of this view receives support, apart from
mechanical principles, from the fact that the mass of the body of any
one of these sponges is greater relatively to the total flagellated area
than in those sponges with eurypylous chambers; that is to say, a
few aphodal and diplodal chambers are as efficient as many of the
eurypylous type.

It is manifest that the current is the bearer of the supply of food; but
it requires more care to discover (1) what is the nature of the food;
(2) by which of the cells bathed by the current the food is captured
and by which digested. The answer to the latter question has long
been sought by experimenters,[275] who supplied the living sponge
with finely powdered coloured matters, such as carmine, indigo,
charcoal, suspended in water. The results received conflicting
interpretations until it became recognised that it was essential to take
into account the length of time during which the sponge had been
fed before its tissues were subjected to microscopic examination.
Vosmaer and Pekelharing obtained the following facts: Spongilla
lacustris and Sycon ciliatum, when killed after feeding for from half
an hour to two hours with milk or carmine, contain these substances
in abundance in the bodies of the choanocytes and to a slight degree
in the deeper cells of the dermal tissue; after feeding for twenty-four
hours the proportions are reversed, and if a period of existence in
water uncharged with carmine intervenes between the long feed and
death then the chambers are completely free from carmine. These
are perhaps the most conclusive experiments yet described, and
they show that the choanocytes ingest solid particles and that the
amoeboid cells of the dermal layer receive the ingested matter from
them. In all probability it is fair to argue from these facts that solid
particles of matter suitable to form food for the sponge are similarly
dealt with by it and undergo digestion in the dermal cells.

Choanocytes are the feeding organs par excellence; but the


pinacocytes perform a small share of the function of ingestion, and in
the higher sponges where the dermal tissue has acquired a great
bulk the share is perhaps increased.

In the above experiments is implied the tacit assumption that


sponges take their food in the form of finely divided solids.
Haeckel[276] states his opinion that they feed on solid particles
derived from decaying organisms, but that possibly decaying
substances in solution may eke out their diet. Loisel, in 1898,[277]
made a new departure in the field of experiment by feeding sponges
with coloured solutions, and obtained valuable results. Thus
solutions, if presented to the sponge in a state of extreme dilution,
are subjected to choice, some being absorbed, some rejected. When
absorbed they are accumulated in vacuoles within both dermal and
gastral cells, mixed solutions are separated into their constituents
and collected into separate vacuoles. In the vacuoles the solutions
may undergo change; Congo red becomes violet, the colour which it
assumes when treated with acid, and similarly blue litmus turns red.
The contents of the vacuoles, sometimes modified, sometimes not,
are poured out into the intercellular gelatinous matrix of the dermal
layer, whence they are removed partly by amoeboid cells, partly, so
Loisel thinks, by the action of the matrix itself. It adds to the value of
these observations to learn that Loisel kept a Spongilla supplied with
filtered spring-water, to which was added the filtered juice obtained
from another crushed sponge. This Spongilla lived and budded, and
was in good health at the end of ten days.

Movement.—Sponges are capable of locomotion only in the young


stage; in the adult the only signs of movement are the exhalant
current, and in some cases movements of contraction sufficiently
marked to be visible to the naked eye. Meresjkowsky was one of the
early observers of these movements. He mentions that he stimulated
a certain corticate Monaxonid sponge by means of a needle point: a
definite response to each prick inside the oscular rim was given by
the speedy contraction of the osculum.[278]

Pigments and Spicules.—Various reasons lead one to conclude


that the spicules have some function other than that of support and
defence, probably connected with metabolism. For the spicules are
cast off, sometimes in large numbers, to be replaced rapidly by new
ones, a process for which it is difficult to find an adequate
explanation if the spicules are regarded as merely skeletal and
defensive.[279] Potts remarks upon the striking profusion with which
spicules are secreted by developing Spongillids from water in which
the percentage of silica present must have been exceedingly small.
The young sponges climbed up the strands of spicules as they
formed them, leaving the lower parts behind and adding to the upper
ends.
Of the physiology of the pigments of sponges not much is yet known:
a useful summary of facts will be found in Von Fürth's text-book.[280]

Spongin.—Von Fürth[280] points out that this term is really a


collective one, seeing that the identity of the organic skeletal
substance of all sponge species is hardly to be assumed. Spongin is
remarkable for containing iodine. The amount of iodine present in
different sponges varies widely, reaching in certain tropical species
of the Aplysinidae and Spongidae the high figure 8 to 14 per cent.
Seaweeds which are specially rich in iodine contain only 1.5 to 1.6
per cent.

In view of the fact that iodine is a specific for croup, it is of interest to


observe that the old herb doctors for many centuries recognised the
bath sponge as a cure for that disease.
Fig. 122.—The ordinals measure (i.) the number of species, a-f, and (ii.) the
number of stations, a'-f', at which successful hauls were made. The
abscissae measure the depth: thus at I. the depth is from 0 to 50 fathoms;
at II. from 51 to 200; at III. from 201 to 1000; at IV. from 1001 upwards. a, a',
are the curves for Sponges generally; b, b', for Monaxonida; c, c', for
Hexactinellida; d, d', for Tetractinellida; e, e', for Calcarea; f, f', for Ceratosa.

Distribution in Space.—All the larger groups of Sponges are


cosmopolitan. Each group has, however, its characteristic
bathymetrical range: the facts are best displayed by means of
curves, as in Fig. 122, which is based wholly on the results obtained
by the "Challenger" Expedition. The information as to littoral species
is consequently inadequate, and we have not the data requisite for
their discussion.

Sponges generally (a) and Monaxonida in particular (b) are more


generally distributed in water of depths of 51 to 200 fathoms than in
depths of less than 50 fathoms; but localities in shallow water are
richer, for the station curve (a') rises abruptly from I. to II., while the
species curve (a) in the same region is almost horizontal.

The Hexactinellid curve (c) culminates on III., showing that the group
is characteristically deep water. That for Tetractinellida (d) reaches
its greatest height on II., i.e. between 51 and 200 fathoms. Even

Вам также может понравиться